pi-spi-sdk 0.1.2 → 0.2.0

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 (215) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/README.md +23 -1
  3. package/dist/chunk-7W56NW2S.mjs +2066 -0
  4. package/dist/generated-FM5EVVHH.mjs +84 -0
  5. package/dist/index.cjs +4754 -0
  6. package/dist/index.d.cts +4940 -0
  7. package/dist/index.d.ts +4937 -11
  8. package/dist/index.mjs +2359 -0
  9. package/dist/index.umd.js +2 -0
  10. package/dist/qrcode/index.cjs +757 -0
  11. package/dist/qrcode/index.d.cts +68 -0
  12. package/dist/qrcode/index.d.ts +68 -0
  13. package/dist/qrcode/index.mjs +712 -0
  14. package/package.json +25 -8
  15. package/dist/config.d.ts +0 -35
  16. package/dist/config.js +0 -4
  17. package/dist/error-handler.d.ts +0 -7
  18. package/dist/error-handler.js +0 -52
  19. package/dist/errors.d.ts +0 -25
  20. package/dist/errors.js +0 -40
  21. package/dist/examples.d.ts +0 -8
  22. package/dist/examples.js +0 -91
  23. package/dist/generated/core/ApiError.d.ts +0 -10
  24. package/dist/generated/core/ApiError.js +0 -11
  25. package/dist/generated/core/ApiRequestOptions.d.ts +0 -13
  26. package/dist/generated/core/ApiRequestOptions.js +0 -1
  27. package/dist/generated/core/ApiResult.d.ts +0 -7
  28. package/dist/generated/core/ApiResult.js +0 -1
  29. package/dist/generated/core/CancelablePromise.d.ts +0 -20
  30. package/dist/generated/core/CancelablePromise.js +0 -111
  31. package/dist/generated/core/OpenAPI.d.ts +0 -16
  32. package/dist/generated/core/OpenAPI.js +0 -11
  33. package/dist/generated/core/request.d.ts +0 -34
  34. package/dist/generated/core/request.js +0 -269
  35. package/dist/generated/index.d.ts +0 -78
  36. package/dist/generated/index.js +0 -43
  37. package/dist/generated/models/AliasCreationReponse.d.ts +0 -22
  38. package/dist/generated/models/AliasCreationReponse.js +0 -1
  39. package/dist/generated/models/AliasCreationRequest.d.ts +0 -11
  40. package/dist/generated/models/AliasCreationRequest.js +0 -1
  41. package/dist/generated/models/AliasReponseListe.d.ts +0 -26
  42. package/dist/generated/models/AliasReponseListe.js +0 -1
  43. package/dist/generated/models/AnnulationStatut.d.ts +0 -13
  44. package/dist/generated/models/AnnulationStatut.js +0 -18
  45. package/dist/generated/models/Champs.d.ts +0 -1
  46. package/dist/generated/models/Champs.js +0 -1
  47. package/dist/generated/models/CompteOperation.d.ts +0 -72
  48. package/dist/generated/models/CompteOperation.js +0 -24
  49. package/dist/generated/models/CompteOperationListe.d.ts +0 -18
  50. package/dist/generated/models/CompteOperationListe.js +0 -1
  51. package/dist/generated/models/CompteSolde.d.ts +0 -129
  52. package/dist/generated/models/CompteSolde.js +0 -71
  53. package/dist/generated/models/CompteTransfertIntraReponse.d.ts +0 -33
  54. package/dist/generated/models/CompteTransfertIntraReponse.js +0 -12
  55. package/dist/generated/models/CompteTransfertIntraRequest.d.ts +0 -9
  56. package/dist/generated/models/CompteTransfertIntraRequest.js +0 -1
  57. package/dist/generated/models/DemandePaiementConfirmationAnnulationRaison.d.ts +0 -14
  58. package/dist/generated/models/DemandePaiementConfirmationAnnulationRaison.js +0 -19
  59. package/dist/generated/models/DemandePaiementConfirmationReponse.d.ts +0 -41
  60. package/dist/generated/models/DemandePaiementConfirmationReponse.js +0 -13
  61. package/dist/generated/models/DemandePaiementConfirmationRequest.d.ts +0 -3
  62. package/dist/generated/models/DemandePaiementConfirmationRequest.js +0 -1
  63. package/dist/generated/models/DemandePaiementConfirmationRequestAccepter.d.ts +0 -9
  64. package/dist/generated/models/DemandePaiementConfirmationRequestAccepter.js +0 -1
  65. package/dist/generated/models/DemandePaiementConfirmationRequestRejeter.d.ts +0 -9
  66. package/dist/generated/models/DemandePaiementConfirmationRequestRejeter.js +0 -1
  67. package/dist/generated/models/DemandePaiementConsultationReponse.d.ts +0 -151
  68. package/dist/generated/models/DemandePaiementConsultationReponse.js +0 -27
  69. package/dist/generated/models/DemandePaiementEnMasseConfirmationRequest.d.ts +0 -3
  70. package/dist/generated/models/DemandePaiementEnMasseConfirmationRequest.js +0 -1
  71. package/dist/generated/models/DemandePaiementEnMasseConfirmationRequestAccepter.d.ts +0 -9
  72. package/dist/generated/models/DemandePaiementEnMasseConfirmationRequestAccepter.js +0 -1
  73. package/dist/generated/models/DemandePaiementEnMasseConfirmationRequestRejeter.d.ts +0 -9
  74. package/dist/generated/models/DemandePaiementEnMasseConfirmationRequestRejeter.js +0 -1
  75. package/dist/generated/models/DemandePaiementEnMasseRequest.d.ts +0 -74
  76. package/dist/generated/models/DemandePaiementEnMasseRequest.js +0 -1
  77. package/dist/generated/models/DemandePaiementEnMasseStatutReponse.d.ts +0 -98
  78. package/dist/generated/models/DemandePaiementEnMasseStatutReponse.js +0 -20
  79. package/dist/generated/models/DemandePaiementListe.d.ts +0 -26
  80. package/dist/generated/models/DemandePaiementListe.js +0 -1
  81. package/dist/generated/models/DemandePaiementListeItem.d.ts +0 -163
  82. package/dist/generated/models/DemandePaiementListeItem.js +0 -27
  83. package/dist/generated/models/DemandePaiementReponse.d.ts +0 -129
  84. package/dist/generated/models/DemandePaiementReponse.js +0 -1
  85. package/dist/generated/models/DemandePaiementReponseRequest.d.ts +0 -21
  86. package/dist/generated/models/DemandePaiementReponseRequest.js +0 -11
  87. package/dist/generated/models/DemandePaiementRequest.d.ts +0 -98
  88. package/dist/generated/models/DemandePaiementRequest.js +0 -7
  89. package/dist/generated/models/DemandePaiementRequestBase.d.ts +0 -42
  90. package/dist/generated/models/DemandePaiementRequestBase.js +0 -1
  91. package/dist/generated/models/DemandePaiementRequestCategorie.d.ts +0 -12
  92. package/dist/generated/models/DemandePaiementRequestCategorie.js +0 -17
  93. package/dist/generated/models/DemandePaiementStatut.d.ts +0 -13
  94. package/dist/generated/models/DemandePaiementStatut.js +0 -18
  95. package/dist/generated/models/DemandePaiementStatutRaison.d.ts +0 -46
  96. package/dist/generated/models/DemandePaiementStatutRaison.js +0 -51
  97. package/dist/generated/models/ListeMeta.d.ts +0 -14
  98. package/dist/generated/models/ListeMeta.js +0 -1
  99. package/dist/generated/models/Paiement.d.ts +0 -156
  100. package/dist/generated/models/Paiement.js +0 -28
  101. package/dist/generated/models/PaiementAnnulationMotif.d.ts +0 -17
  102. package/dist/generated/models/PaiementAnnulationMotif.js +0 -22
  103. package/dist/generated/models/PaiementAnnulationReponseRequest.d.ts +0 -11
  104. package/dist/generated/models/PaiementAnnulationReponseRequest.js +0 -1
  105. package/dist/generated/models/PaiementAnnulationReponseRequestAccepter.d.ts +0 -9
  106. package/dist/generated/models/PaiementAnnulationReponseRequestAccepter.js +0 -1
  107. package/dist/generated/models/PaiementAnnulationReponseRequestRejeter.d.ts +0 -9
  108. package/dist/generated/models/PaiementAnnulationReponseRequestRejeter.js +0 -1
  109. package/dist/generated/models/PaiementAnnulationRequest.d.ts +0 -4
  110. package/dist/generated/models/PaiementAnnulationRequest.js +0 -1
  111. package/dist/generated/models/PaiementAnnulationStatutRaison.d.ts +0 -21
  112. package/dist/generated/models/PaiementAnnulationStatutRaison.js +0 -26
  113. package/dist/generated/models/PaiementEnMasseConfirmationRequest.d.ts +0 -3
  114. package/dist/generated/models/PaiementEnMasseConfirmationRequest.js +0 -1
  115. package/dist/generated/models/PaiementEnMasseConfirmationRequestAccepter.d.ts +0 -9
  116. package/dist/generated/models/PaiementEnMasseConfirmationRequestAccepter.js +0 -1
  117. package/dist/generated/models/PaiementEnMasseConfirmationRequestRejeter.d.ts +0 -9
  118. package/dist/generated/models/PaiementEnMasseConfirmationRequestRejeter.js +0 -1
  119. package/dist/generated/models/PaiementEnMasseReponseStatut.d.ts +0 -97
  120. package/dist/generated/models/PaiementEnMasseReponseStatut.js +0 -20
  121. package/dist/generated/models/PaiementEnMasseRequest.d.ts +0 -54
  122. package/dist/generated/models/PaiementEnMasseRequest.js +0 -1
  123. package/dist/generated/models/PaiementImmediatConfirmationReponse.d.ts +0 -31
  124. package/dist/generated/models/PaiementImmediatConfirmationReponse.js +0 -7
  125. package/dist/generated/models/PaiementImmediatConfirmationRequest.d.ts +0 -3
  126. package/dist/generated/models/PaiementImmediatConfirmationRequest.js +0 -1
  127. package/dist/generated/models/PaiementImmediatConfirmationRequestAccepter.d.ts +0 -9
  128. package/dist/generated/models/PaiementImmediatConfirmationRequestAccepter.js +0 -1
  129. package/dist/generated/models/PaiementImmediatConfirmationRequestRejeter.d.ts +0 -9
  130. package/dist/generated/models/PaiementImmediatConfirmationRequestRejeter.js +0 -1
  131. package/dist/generated/models/PaiementImmediatReponse.d.ts +0 -98
  132. package/dist/generated/models/PaiementImmediatReponse.js +0 -7
  133. package/dist/generated/models/PaiementImmediatRequest.d.ts +0 -13
  134. package/dist/generated/models/PaiementImmediatRequest.js +0 -1
  135. package/dist/generated/models/PaiementListe.d.ts +0 -6
  136. package/dist/generated/models/PaiementListe.js +0 -1
  137. package/dist/generated/models/PaiementRequest.d.ts +0 -33
  138. package/dist/generated/models/PaiementRequest.js +0 -1
  139. package/dist/generated/models/PaiementStatut.d.ts +0 -13
  140. package/dist/generated/models/PaiementStatut.js +0 -18
  141. package/dist/generated/models/PaiementStatutRaison.d.ts +0 -56
  142. package/dist/generated/models/PaiementStatutRaison.js +0 -61
  143. package/dist/generated/models/Problem7807.d.ts +0 -31
  144. package/dist/generated/models/Problem7807.js +0 -1
  145. package/dist/generated/models/RefDocType.d.ts +0 -38
  146. package/dist/generated/models/RefDocType.js +0 -43
  147. package/dist/generated/models/RetourStatut.d.ts +0 -13
  148. package/dist/generated/models/RetourStatut.js +0 -18
  149. package/dist/generated/models/RetourStatutRaison.d.ts +0 -25
  150. package/dist/generated/models/RetourStatutRaison.js +0 -30
  151. package/dist/generated/models/WebhookCreationRequest.d.ts +0 -14
  152. package/dist/generated/models/WebhookCreationRequest.js +0 -1
  153. package/dist/generated/models/WebhookCreationResponse.d.ts +0 -12
  154. package/dist/generated/models/WebhookCreationResponse.js +0 -1
  155. package/dist/generated/models/WebhookData.d.ts +0 -8
  156. package/dist/generated/models/WebhookData.js +0 -1
  157. package/dist/generated/models/WebhookEvent.d.ts +0 -191
  158. package/dist/generated/models/WebhookEvent.js +0 -42
  159. package/dist/generated/models/WebhookEventsList.d.ts +0 -13
  160. package/dist/generated/models/WebhookEventsList.js +0 -1
  161. package/dist/generated/models/WebhookList.d.ts +0 -13
  162. package/dist/generated/models/WebhookList.js +0 -1
  163. package/dist/generated/models/WebhookModificationRequest.d.ts +0 -4
  164. package/dist/generated/models/WebhookModificationRequest.js +0 -1
  165. package/dist/generated/models/WebhooksEvents.d.ts +0 -12
  166. package/dist/generated/models/WebhooksEvents.js +0 -17
  167. package/dist/generated/services/AliasService.d.ts +0 -63
  168. package/dist/generated/services/AliasService.js +0 -84
  169. package/dist/generated/services/ComptesService.d.ts +0 -64
  170. package/dist/generated/services/ComptesService.js +0 -86
  171. package/dist/generated/services/DemandeAnnulationService.d.ts +0 -84
  172. package/dist/generated/services/DemandeAnnulationService.js +0 -99
  173. package/dist/generated/services/DemandesDePaiementEnMasseService.d.ts +0 -161
  174. package/dist/generated/services/DemandesDePaiementEnMasseService.js +0 -189
  175. package/dist/generated/services/DemandesDePaiementService.d.ts +0 -123
  176. package/dist/generated/services/DemandesDePaiementService.js +0 -161
  177. package/dist/generated/services/NotificationService.d.ts +0 -80
  178. package/dist/generated/services/NotificationService.js +0 -132
  179. package/dist/generated/services/PaiementEnMasseService.d.ts +0 -159
  180. package/dist/generated/services/PaiementEnMasseService.js +0 -187
  181. package/dist/generated/services/PaiementImmediatService.d.ts +0 -135
  182. package/dist/generated/services/PaiementImmediatService.js +0 -176
  183. package/dist/generated/services/RetoursdeFondsService.d.ts +0 -28
  184. package/dist/generated/services/RetoursdeFondsService.js +0 -37
  185. package/dist/index.js +0 -23
  186. package/dist/query-builder.d.ts +0 -91
  187. package/dist/query-builder.js +0 -187
  188. package/dist/sdk.d.ts +0 -88
  189. package/dist/sdk.js +0 -107
  190. package/dist/services/alias.d.ts +0 -72
  191. package/dist/services/alias.js +0 -82
  192. package/dist/services/base.d.ts +0 -9
  193. package/dist/services/base.js +0 -17
  194. package/dist/services/comptes.d.ts +0 -149
  195. package/dist/services/comptes.js +0 -158
  196. package/dist/services/demandes-annulation.d.ts +0 -97
  197. package/dist/services/demandes-annulation.js +0 -104
  198. package/dist/services/demandes-paiement-en-masse.d.ts +0 -139
  199. package/dist/services/demandes-paiement-en-masse.js +0 -139
  200. package/dist/services/demandes-paiement.d.ts +0 -144
  201. package/dist/services/demandes-paiement.js +0 -151
  202. package/dist/services/paiements-en-masse.d.ts +0 -152
  203. package/dist/services/paiements-en-masse.js +0 -153
  204. package/dist/services/paiements.d.ts +0 -135
  205. package/dist/services/paiements.js +0 -135
  206. package/dist/services/retours-fonds.d.ts +0 -94
  207. package/dist/services/retours-fonds.js +0 -100
  208. package/dist/services/webhooks.d.ts +0 -131
  209. package/dist/services/webhooks.js +0 -142
  210. package/dist/types/alias.d.ts +0 -64
  211. package/dist/types/alias.js +0 -73
  212. package/dist/utils/constants.d.ts +0 -93
  213. package/dist/utils/constants.js +0 -93
  214. package/dist/utils/index.d.ts +0 -60
  215. package/dist/utils/index.js +0 -115
package/dist/index.mjs ADDED
@@ -0,0 +1,2359 @@
1
+ import {
2
+ AliasService,
3
+ AnnulationStatut,
4
+ ApiError,
5
+ CancelError,
6
+ CancelablePromise,
7
+ CompteOperation,
8
+ CompteSolde,
9
+ CompteTransfertIntraReponse,
10
+ ComptesService,
11
+ DemandeAnnulationService,
12
+ DemandePaiementConfirmationAnnulationRaison,
13
+ DemandePaiementConfirmationReponse,
14
+ DemandePaiementConsultationReponse,
15
+ DemandePaiementEnMasseStatutReponse,
16
+ DemandePaiementListeItem,
17
+ DemandePaiementReponseRequest,
18
+ DemandePaiementRequest,
19
+ DemandePaiementRequestCategorie,
20
+ DemandePaiementStatut,
21
+ DemandePaiementStatutRaison,
22
+ DemandesDePaiementEnMasseService,
23
+ DemandesDePaiementService,
24
+ NotificationService,
25
+ OpenAPI,
26
+ Paiement,
27
+ PaiementAnnulationMotif,
28
+ PaiementAnnulationStatutRaison,
29
+ PaiementEnMasseReponseStatut,
30
+ PaiementEnMasseService,
31
+ PaiementImmediatConfirmationReponse,
32
+ PaiementImmediatReponse,
33
+ PaiementImmediatService,
34
+ PaiementStatut,
35
+ PaiementStatutRaison,
36
+ RefDocType,
37
+ RetourStatut,
38
+ RetourStatutRaison,
39
+ RetoursdeFondsService,
40
+ WebhookEvent,
41
+ WebhooksEvents
42
+ } from "./chunk-7W56NW2S.mjs";
43
+
44
+ // src/errors.ts
45
+ var PiSpiError = class extends Error {
46
+ constructor(message, statusCode, statusText, type, detail, instance) {
47
+ super(message);
48
+ this.name = "PiSpiError";
49
+ this.statusCode = statusCode;
50
+ this.statusText = statusText;
51
+ this.type = type;
52
+ this.detail = detail;
53
+ this.instance = instance;
54
+ }
55
+ };
56
+ var PiSpiValidationError = class extends PiSpiError {
57
+ constructor(message, statusCode, statusText, errors, type, detail) {
58
+ super(message, statusCode, statusText, type, detail);
59
+ this.name = "PiSpiValidationError";
60
+ this.errors = errors;
61
+ }
62
+ };
63
+ var PiSpiAuthError = class extends PiSpiError {
64
+ constructor(message, statusCode, statusText) {
65
+ super(message, statusCode, statusText);
66
+ this.name = "PiSpiAuthError";
67
+ }
68
+ };
69
+ var PiSpiNotFoundError = class extends PiSpiError {
70
+ constructor(message, statusCode, statusText) {
71
+ super(message, statusCode, statusText);
72
+ this.name = "PiSpiNotFoundError";
73
+ }
74
+ };
75
+ var PiSpiRateLimitError = class extends PiSpiError {
76
+ constructor(message, statusCode, statusText, retryAfter) {
77
+ super(message, statusCode, statusText);
78
+ this.name = "PiSpiRateLimitError";
79
+ this.retryAfter = retryAfter;
80
+ }
81
+ };
82
+
83
+ // src/error-handler.ts
84
+ function handleApiError(error) {
85
+ const isApiError = error && typeof error === "object" && "status" in error && "statusText" in error && "body" in error;
86
+ if (isApiError) {
87
+ const apiError = error;
88
+ const status = apiError.status;
89
+ const body = apiError.body;
90
+ const type = body?.type;
91
+ const title = body?.title || apiError.statusText;
92
+ const detail = body?.detail || apiError.message;
93
+ const instance = body?.instance;
94
+ if (status === 400) {
95
+ const invalidParams = body?.invalidParams || body?.errors;
96
+ throw new PiSpiValidationError(
97
+ detail || title || "Validation error",
98
+ status,
99
+ apiError.statusText,
100
+ invalidParams,
101
+ type,
102
+ detail
103
+ );
104
+ }
105
+ if (status === 401) {
106
+ throw new PiSpiAuthError(
107
+ detail || title || "Authentication failed",
108
+ status,
109
+ apiError.statusText
110
+ );
111
+ }
112
+ if (status === 403) {
113
+ throw new PiSpiError(
114
+ detail || title || "Forbidden",
115
+ status,
116
+ apiError.statusText,
117
+ type,
118
+ detail,
119
+ instance
120
+ );
121
+ }
122
+ if (status === 404) {
123
+ throw new PiSpiNotFoundError(
124
+ detail || title || "Resource not found",
125
+ status,
126
+ apiError.statusText
127
+ );
128
+ }
129
+ if (status === 429) {
130
+ throw new PiSpiRateLimitError(
131
+ detail || title || "Rate limit exceeded",
132
+ status,
133
+ apiError.statusText
134
+ );
135
+ }
136
+ throw new PiSpiError(
137
+ detail || title || apiError.message || "API error",
138
+ status,
139
+ apiError.statusText,
140
+ type,
141
+ detail,
142
+ instance
143
+ );
144
+ }
145
+ throw error;
146
+ }
147
+
148
+ // src/services/base.ts
149
+ var BaseService = class {
150
+ constructor(config) {
151
+ this.config = config;
152
+ }
153
+ /**
154
+ * Wrap an async operation with error handling
155
+ */
156
+ async execute(operation) {
157
+ try {
158
+ return await operation();
159
+ } catch (error) {
160
+ throw handleApiError(error);
161
+ }
162
+ }
163
+ /**
164
+ * Make an HTTP request
165
+ */
166
+ async request(method, path, body, params) {
167
+ return this.execute(async () => {
168
+ const url = new URL(`${this.config.BASE}${path}`);
169
+ if (params) {
170
+ Object.entries(params).forEach(([key, value]) => {
171
+ if (value !== void 0 && value !== null) {
172
+ url.searchParams.append(key, String(value));
173
+ }
174
+ });
175
+ }
176
+ const headers = {
177
+ "Content-Type": "application/json",
178
+ "Accept": "application/json",
179
+ ...this.config.HEADERS
180
+ };
181
+ if (this.config.TOKEN) {
182
+ headers["Authorization"] = `Bearer ${this.config.TOKEN}`;
183
+ }
184
+ const fetchOptions = {
185
+ method,
186
+ headers,
187
+ body: body ? JSON.stringify(body) : void 0
188
+ };
189
+ if (this.config.dispatcher) {
190
+ fetchOptions.dispatcher = this.config.dispatcher;
191
+ }
192
+ const response = await fetch(url.toString(), fetchOptions);
193
+ if (!response.ok) {
194
+ let errorBody;
195
+ try {
196
+ const parsed = await response.json();
197
+ errorBody = {
198
+ ...parsed,
199
+ status: response.status,
200
+ statusText: response.statusText
201
+ };
202
+ } catch {
203
+ errorBody = {
204
+ status: response.status,
205
+ statusText: response.statusText
206
+ };
207
+ }
208
+ throw errorBody;
209
+ }
210
+ if (response.status === 204) {
211
+ return {};
212
+ }
213
+ return await response.json();
214
+ });
215
+ }
216
+ };
217
+
218
+ // src/services/comptes.ts
219
+ var ComptesService2 = class extends BaseService {
220
+ /**
221
+ * Get account details and balance
222
+ *
223
+ * **Returns:**
224
+ * - Account type (CACC, SVGS, etc.)
225
+ * - Account number
226
+ * - Current balance (`solde` in centimes)
227
+ * - Account status (OUVERT, BLOQUE, CLOTURE)
228
+ * - Opening date
229
+ * - Pre-confirmation indicator
230
+ *
231
+ * @param numero - Account number (e.g., 'CIC2344256727788288822')
232
+ * @returns Account details including balance
233
+ * @throws {PiSpiNotFoundError} If account not found
234
+ * @throws {PiSpiAuthError} If authentication fails
235
+ *
236
+ * @example
237
+ * ```typescript
238
+ * const account = await sdk.comptes.getAccount('CIC2344256727788288822');
239
+ * // Returns: {
240
+ * // type: 'CACC',
241
+ * // numero: 'CIC2344256727788288822',
242
+ * // solde: 150000000, // 1,500,000 XOF in centimes
243
+ * // statut: 'OUVERT',
244
+ * // dateOuverture: '2023-02-21T15:30:01.250Z'
245
+ * // }
246
+ * ```
247
+ */
248
+ async getAccount(numero) {
249
+ return this.request("GET", `/comptes/${encodeURIComponent(numero)}`);
250
+ }
251
+ /**
252
+ * List account operations (transactions)
253
+ *
254
+ * **Filtering Options:**
255
+ * - Filter by account number (`comptePayeur`, `comptePaye`)
256
+ * - Filter by status (`statut`: INITIE, ENVOYE, IRREVOCABLE, REJETE)
257
+ * - Filter by dates (`dateEnvoi`, `dateIrrevocabilite`)
258
+ * - Use QueryBuilder for advanced filtering
259
+ *
260
+ * @param params - Query parameters for filtering and pagination
261
+ * @param params.comptePayeur - Filter by payer account number
262
+ * @param params.comptePaye - Filter by payee account number
263
+ * @param params.statut - Filter by transaction status
264
+ * @param params.dateEnvoi - Filter by send date
265
+ * @param params.dateIrrevocabilite - Filter by irrevocability date
266
+ * @param params.page - Page number (default: 1)
267
+ * @param params.size - Page size (default: 20, max: 100)
268
+ * @returns Paginated list of operations
269
+ *
270
+ * @example
271
+ * ```typescript
272
+ * // List all operations for an account
273
+ * const operations = await sdk.comptes.listOperations({
274
+ * comptePayeur: 'CIC2344256727788288822',
275
+ * page: 1,
276
+ * size: 20
277
+ * });
278
+ *
279
+ * // Filter by status
280
+ * const completed = await sdk.comptes.listOperations({
281
+ * comptePayeur: 'CIC2344256727788288822',
282
+ * statut: 'IRREVOCABLE'
283
+ * });
284
+ * ```
285
+ */
286
+ async listOperations(params) {
287
+ return this.request("GET", "/comptes/transactions", void 0, params);
288
+ }
289
+ /**
290
+ * Transfer funds between accounts owned by the same client
291
+ *
292
+ * **Intra-Account Transfer:**
293
+ * - Transfers between accounts owned by the same legal entity
294
+ * - Accounts must be at the same financial institution
295
+ * - Can use account numbers or aliases
296
+ *
297
+ * **Transfer Methods:**
298
+ * - Using account numbers: `comptePayeur` and `comptePaye`
299
+ * - Using aliases: `payeurAlias` and `payeAlias`
300
+ *
301
+ * @param transfer - Transfer request details
302
+ * @param transfer.comptePayeur - Payer account number (if using account numbers)
303
+ * @param transfer.comptePaye - Payee account number (if using account numbers)
304
+ * @param transfer.payeurAlias - Payer alias (if using aliases)
305
+ * @param transfer.payeAlias - Payee alias (if using aliases)
306
+ * @param transfer.montant - Amount in centimes (e.g., 150000 = 1,500 XOF)
307
+ * @param transfer.motif - Transfer reason/description
308
+ * @param transfer.txId - Unique transaction ID (optional, auto-generated if not provided)
309
+ * @returns Transfer response with status
310
+ * @throws {PiSpiValidationError} If transfer fails validation
311
+ * @throws {PiSpiError} If account blocked or insufficient funds
312
+ *
313
+ * @example
314
+ * ```typescript
315
+ * // Transfer using account numbers
316
+ * await sdk.comptes.transfer({
317
+ * comptePayeur: 'CIC2344256727788288822',
318
+ * comptePaye: 'SNC2344256727788288822',
319
+ * montant: 150000, // 1,500 XOF
320
+ * motif: 'Transfert de fonds',
321
+ * txId: '23511722'
322
+ * });
323
+ *
324
+ * // Transfer using aliases
325
+ * await sdk.comptes.transfer({
326
+ * payeurAlias: '8b1b2499-3e50-435b-b757-ac7a83d8aa7f',
327
+ * payeAlias: '4r5ty499-3e50-435b-b757-ac7a83d67juio',
328
+ * montant: 150000,
329
+ * motif: 'Transfert entre comptes'
330
+ * });
331
+ * ```
332
+ */
333
+ async transfer(transfer) {
334
+ const txId = transfer.txId ?? `TRF-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
335
+ return this.request("POST", "/comptes/transactions", {
336
+ txId,
337
+ comptePayeur: transfer.comptePayeur,
338
+ comptePaye: transfer.comptePaye,
339
+ payeurAlias: transfer.payeurAlias,
340
+ payeAlias: transfer.payeAlias,
341
+ montant: transfer.montant,
342
+ motif: transfer.motif
343
+ });
344
+ }
345
+ };
346
+
347
+ // src/services/alias.ts
348
+ var AliasService2 = class extends BaseService {
349
+ /**
350
+ * Create an account alias
351
+ *
352
+ * **Alias Types:**
353
+ * - `SHID`: System-generated unique payment address (UUID format, 36 chars). Available for all client types (P, C, B, G)
354
+ * - `MCOD`: Merchant code for USSD payments. Available for business clients only (C, B, G)
355
+ * - `MBNO`: Mobile phone number. Available for individuals only (P)
356
+ *
357
+ * **Limits:**
358
+ * - Default: 20 aliases per account
359
+ * - Limit can be increased based on client needs
360
+ *
361
+ * @param alias - Alias creation data
362
+ * @param alias.compte - Account number (e.g., 'CIC2344256727788288822')
363
+ * @param alias.type - Alias type: 'SHID', 'MCOD', or 'MBNO'
364
+ * @returns Created alias with generated `cle` (key) value
365
+ * @throws {PiSpiError} If account not found or limit exceeded
366
+ *
367
+ * @example
368
+ * ```typescript
369
+ * // For business clients (C, B, G)
370
+ * await sdk.alias.create({
371
+ * compte: 'SNC2344256727788288822',
372
+ * type: AliasType.SHID
373
+ * });
374
+ * ```
375
+ */
376
+ async create(alias) {
377
+ return this.request(
378
+ "POST",
379
+ `/comptes/${encodeURIComponent(alias.compte)}/alias`,
380
+ { type: alias.type }
381
+ );
382
+ }
383
+ /**
384
+ * List aliases for an account
385
+ *
386
+ * @param compte - Account number
387
+ * @param params - Query parameters for pagination
388
+ * @returns Paginated list of aliases
389
+ */
390
+ async list(compte, params) {
391
+ return this.request("GET", `/comptes/${encodeURIComponent(compte)}/alias`, void 0, params);
392
+ }
393
+ /**
394
+ * Delete an alias
395
+ *
396
+ * @param alias - Alias identifier
397
+ */
398
+ async delete(alias, compte) {
399
+ if (!compte) {
400
+ throw new Error("Account number (compte) is required to delete an alias.");
401
+ }
402
+ return this.request(
403
+ "DELETE",
404
+ `/comptes/${encodeURIComponent(compte)}/alias/${encodeURIComponent(alias)}`
405
+ );
406
+ }
407
+ };
408
+
409
+ // src/services/webhooks.ts
410
+ var WebhooksService = class extends BaseService {
411
+ /**
412
+ * Create a webhook configuration
413
+ *
414
+ * **Webhook Setup:**
415
+ * - URL must be HTTPS
416
+ * - Server must support mTLS with BCEAO-issued certificate
417
+ * - Server must validate HMAC signatures
418
+ * - Server must respond with 2xx status code
419
+ *
420
+ * **Event Types:**
421
+ * - `PAIEMENT_RECU`: Payment received
422
+ * - `PAIEMENT_ENVOYE`: Payment sent (irreversible)
423
+ * - `PAIEMENT_REJETE`: Payment rejected
424
+ * - `RTP_RECU`: Payment request received
425
+ * - `RTP_REJETE`: Payment request rejected
426
+ * - `RETOUR_ENVOYE`: Fund return sent
427
+ * - `RETOUR_REJETE`: Fund return rejected
428
+ * - `RETOUR_RECU`: Fund return received
429
+ * - `ANNULATION_DEMANDE`: Cancellation request received
430
+ * - `ANNULATION_REJETE`: Cancellation request rejected
431
+ *
432
+ * @param webhook - Webhook configuration
433
+ * @param webhook.callbackUrl - HTTPS URL to receive notifications (must support mTLS)
434
+ * @param webhook.events - Array of event types to subscribe to
435
+ * @param webhook.alias - Optional: Alias-specific webhook (only notifications for this alias)
436
+ * @returns Created webhook configuration
437
+ * @throws {PiSpiValidationError} If URL is invalid or events array is empty
438
+ *
439
+ * @example
440
+ * ```typescript
441
+ * // Webhook for all payment events
442
+ * await sdk.webhooks.create({
443
+ * callbackUrl: 'https://business.example.com/api/webhooks/pi-spi',
444
+ * events: ['PAIEMENT_RECU', 'PAIEMENT_ENVOYE', 'PAIEMENT_REJETE']
445
+ * });
446
+ *
447
+ * // Alias-specific webhook
448
+ * await sdk.webhooks.create({
449
+ * callbackUrl: 'https://business.example.com/api/webhooks/pi-spi',
450
+ * events: ['PAIEMENT_RECU'],
451
+ * alias: '8b1b2499-3e50-435b-b757-ac7a83d8aa7f'
452
+ * });
453
+ * ```
454
+ */
455
+ async create(webhook) {
456
+ return this.request("POST", "/webhooks", webhook);
457
+ }
458
+ /**
459
+ * List all configured webhooks
460
+ *
461
+ * @param params - Query parameters for pagination
462
+ * @returns Paginated list of webhooks
463
+ *
464
+ * @example
465
+ * ```typescript
466
+ * const webhooks = await sdk.webhooks.list({ page: 1, size: 20 });
467
+ * ```
468
+ */
469
+ async list(params) {
470
+ return this.request("GET", "/webhooks", void 0, params);
471
+ }
472
+ /**
473
+ * Get webhook details by ID
474
+ *
475
+ * @param id - Webhook ID
476
+ * @returns Webhook details
477
+ * @throws {PiSpiNotFoundError} If webhook not found
478
+ */
479
+ async get(id) {
480
+ return this.request("GET", `/webhooks/${encodeURIComponent(id)}`);
481
+ }
482
+ /**
483
+ * Update webhook configuration
484
+ *
485
+ * @param id - Webhook ID
486
+ * @param webhook - Updated webhook configuration
487
+ * @param webhook.callbackUrl - New callback URL (optional)
488
+ * @param webhook.events - New event subscriptions (optional)
489
+ * @param webhook.alias - New alias filter (optional)
490
+ * @returns Updated webhook configuration
491
+ * @throws {PiSpiNotFoundError} If webhook not found
492
+ * @throws {PiSpiValidationError} If update fails validation
493
+ *
494
+ * @example
495
+ * ```typescript
496
+ * await sdk.webhooks.update('webhook-001', {
497
+ * callbackUrl: 'https://updated-url.com/webhooks/pi-spi',
498
+ * events: ['PAIEMENT_RECU', 'RTP_RECU']
499
+ * });
500
+ * ```
501
+ */
502
+ async update(id, webhook) {
503
+ return this.request(
504
+ "PUT",
505
+ `/webhooks/${encodeURIComponent(id)}`,
506
+ webhook
507
+ );
508
+ }
509
+ /**
510
+ * Delete a webhook configuration
511
+ *
512
+ * @param id - Webhook ID
513
+ * @throws {PiSpiNotFoundError} If webhook not found
514
+ */
515
+ async delete(id) {
516
+ return this.request("DELETE", `/webhooks/${encodeURIComponent(id)}`);
517
+ }
518
+ };
519
+
520
+ // src/services/demandes-paiement.ts
521
+ var DemandesPaiementService = class extends BaseService {
522
+ /**
523
+ * Create a payment request
524
+ *
525
+ * **Request Types:**
526
+ * - **E-commerce** (`categorie: 521`): Max 3 minutes validity
527
+ * - **POS** (`categorie: 500`): Max 24 hours validity
528
+ * - **Invoice** (`categorie: 401`): Custom due date (up to 90 days)
529
+ *
530
+ * **Confirmation Options:**
531
+ * - `confirmation: false`: Request sent immediately (default for POS)
532
+ * - `confirmation: true`: Returns payer info for verification before sending
533
+ *
534
+ * **Customer Actions:**
535
+ * - Accept & Pay Now: Payment processed immediately
536
+ * - Accept & Pay Later: Payment scheduled (if dateLimiteReponse > 24h)
537
+ * - Reject: Request rejected with reason
538
+ * - Ignore: Request expires after dateLimiteReponse
539
+ *
540
+ * @param request - Payment request creation data
541
+ * @param request.comptePaye - Business account number (payee)
542
+ * @param request.payeurAlias - Customer alias (payer)
543
+ * @param request.montant - Amount in centimes (e.g., 150000 = 1,500 XOF)
544
+ * @param request.categorie - Request category: '500' (POS), '521' (E-commerce), '401' (Invoice)
545
+ * @param request.motif - Payment reason/description
546
+ * @param request.txId - Unique transaction ID (optional)
547
+ * @param request.dateLimitePaiement - Payment due date (required for e-commerce and invoices)
548
+ * @param request.dateLimiteReponse - Response deadline (default: 90 days from creation)
549
+ * @param request.confirmation - Whether to require confirmation (default: false for POS, true for invoices)
550
+ * @param request.refDocType - Reference document type (e.g., 'CINV' for invoice)
551
+ * @param request.refDocNumero - Reference document number (e.g., invoice number)
552
+ * @returns Payment request response
553
+ * @throws {PiSpiValidationError} If request fails validation
554
+ *
555
+ * @example
556
+ * ```typescript
557
+ * // E-commerce payment request (3-minute expiry)
558
+ * await sdk.demandesPaiement.create({
559
+ * comptePaye: 'CIC2344256727788288822',
560
+ * payeurAlias: '9b1b3499-3e50-435b-b757-ac7a83d8aa96',
561
+ * montant: 25000, // 250 XOF
562
+ * categorie: '521',
563
+ * dateLimitePaiement: '2023-02-21T15:37:00.000Z', // 3 minutes from now
564
+ * motif: 'Paiement du livre Manuel des écritures comptables'
565
+ * });
566
+ *
567
+ * // Invoice payment request
568
+ * await sdk.demandesPaiement.create({
569
+ * comptePaye: 'CIC2344256727788288822',
570
+ * payeurAlias: '9b1b3499-3e50-435b-b757-ac7a83d8aa96',
571
+ * montant: 150000, // 1,500 XOF
572
+ * categorie: '401',
573
+ * dateLimitePaiement: '2023-12-31T23:59:59.999Z',
574
+ * motif: 'Facture électricité mars 2023',
575
+ * refDocType: 'CINV',
576
+ * refDocNumero: 'FACT-ELEC-202303',
577
+ * confirmation: true
578
+ * });
579
+ * ```
580
+ */
581
+ async create(request) {
582
+ return this.request("POST", "/demandes-paiements", request);
583
+ }
584
+ /**
585
+ * List payment requests with filtering and pagination
586
+ *
587
+ * @param params - Query parameters for filtering and pagination
588
+ * @returns Paginated list of payment requests
589
+ */
590
+ async list(params) {
591
+ return this.request("GET", "/demandes-paiements", void 0, params);
592
+ }
593
+ /**
594
+ * Get payment request details
595
+ *
596
+ * @param id - Payment request transaction ID
597
+ * @returns Payment request details
598
+ * @throws {PiSpiNotFoundError} If request not found
599
+ */
600
+ async get(id) {
601
+ return this.request("GET", `/demandes-paiements/${encodeURIComponent(id)}`);
602
+ }
603
+ /**
604
+ * Accept a payment request
605
+ *
606
+ * **Note:** This is typically called by the customer's payment app, not the business.
607
+ * The business receives notification when customer accepts.
608
+ *
609
+ * @param id - Payment request transaction ID
610
+ * @param immediate - Whether to pay immediately (true) or schedule payment (false)
611
+ * @returns Payment confirmation response
612
+ */
613
+ async accept(id, immediate = true) {
614
+ return this.request(
615
+ "POST",
616
+ `/demandes-paiements/${encodeURIComponent(id)}/reponses`,
617
+ { decision: true, paiementImmediat: immediate }
618
+ );
619
+ }
620
+ /**
621
+ * Reject a payment request
622
+ *
623
+ * **Note:** This is typically called by the customer's payment app, not the business.
624
+ * The business receives notification when customer rejects.
625
+ *
626
+ * @param id - Payment request transaction ID
627
+ * @param reason - Rejection reason code (optional)
628
+ * @returns Rejection confirmation response
629
+ */
630
+ async reject(id, reason) {
631
+ return this.request(
632
+ "POST",
633
+ `/demandes-paiements/${encodeURIComponent(id)}/reponses`,
634
+ { decision: false, ...reason ? { raison: reason } : {} }
635
+ );
636
+ }
637
+ /**
638
+ * Confirm sending a payment request created with confirmation: true
639
+ */
640
+ async confirm(txId, decision) {
641
+ return this.request(
642
+ "PUT",
643
+ `/demandes-paiements/${encodeURIComponent(txId)}/confirmations`,
644
+ { decision }
645
+ );
646
+ }
647
+ };
648
+
649
+ // src/services/demandes-paiement-en-masse.ts
650
+ var DemandesPaiementEnMasseService = class extends BaseService {
651
+ /**
652
+ * Create bulk payment requests
653
+ */
654
+ async create(request) {
655
+ const transactions = request.transactions.map((t) => ({
656
+ ...t,
657
+ categorie: t.categorie || "401"
658
+ }));
659
+ return this.request("POST", "/demandes-paiements-groupes", {
660
+ ...request,
661
+ transactions
662
+ // Use the mapped transactions with defaults
663
+ });
664
+ }
665
+ /**
666
+ * Get bulk payment request details and status
667
+ */
668
+ async get(instructionId) {
669
+ return this.request("GET", `/demandes-paiements-groupes/${instructionId}`);
670
+ }
671
+ /**
672
+ * Confirm and send bulk payment requests
673
+ */
674
+ async confirm(instructionId) {
675
+ return this.request("PUT", `/demandes-paiements-groupes/${instructionId}/confirmations`, {
676
+ decision: true
677
+ });
678
+ }
679
+ };
680
+
681
+ // src/services/paiements.ts
682
+ var PaiementsService = class extends BaseService {
683
+ /**
684
+ * Create an immediate payment
685
+ *
686
+ * **Payment Flow:**
687
+ * - If `confirmation: false`: Payment is sent immediately (default)
688
+ * - If `confirmation: true`: Payment is initiated, returns payee info for confirmation
689
+ *
690
+ * **Supported Transaction Types:**
691
+ * - Bank-to-Bank (`categorie: 733`)
692
+ * - Bank-to-Wallet (via alias lookup)
693
+ * - Wallet-to-Wallet (via alias lookup)
694
+ * - Wallet-to-Bank (via alias lookup)
695
+ *
696
+ * **Status Values:**
697
+ * - `INITIE`: Waiting for confirmation (if confirmation: true)
698
+ * - `ENVOYE`: Payment sent successfully
699
+ * - `IRREVOCABLE`: Payment confirmed and cannot be reversed
700
+ * - `REJETE`: Payment rejected (check `statutRaison` for error code)
701
+ *
702
+ * @param payment - Payment creation data
703
+ * @param payment.comptePayeur - Payer account number (e.g., 'CIC2344256727788288822')
704
+ * @param payment.payeAlias - Payee alias (SHID, MCOD, or MBNO format)
705
+ * @param payment.montant - Amount in centimes (e.g., 150000 = 1,500 XOF)
706
+ * @param payment.motif - Payment reason/description
707
+ * @param payment.txId - Unique transaction ID (optional, auto-generated if not provided)
708
+ * @param payment.confirmation - Whether to require confirmation before sending (default: false)
709
+ * @param payment.categorie - Payment category/canal (default: 733 for API Business)
710
+ * @returns Payment response with status
711
+ * @throws {PiSpiValidationError} If payment fails validation (e.g., invalid alias, duplicate txId)
712
+ * @throws {PiSpiError} If account blocked or insufficient funds
713
+ *
714
+ * @example
715
+ * ```typescript
716
+ * // Immediate payment (no confirmation)
717
+ * const payment = await sdk.paiements.create({
718
+ * comptePayeur: 'CIC2344256727788288822',
719
+ * payeAlias: '8b1b2499-3e50-435b-b757-ac7a83d8aa7f', // SHID alias
720
+ * montant: 150000, // 1,500 XOF
721
+ * motif: 'Paiement de services',
722
+ * txId: '23552722'
723
+ * });
724
+ *
725
+ * // Payment with confirmation (returns payee info)
726
+ * const paymentWithConfirmation = await sdk.paiements.create({
727
+ * comptePayeur: 'CIC2344256727788288822',
728
+ * payeAlias: '8b1b2499-3e50-435b-b757-ac7a83d8aa7f',
729
+ * montant: 3000000, // 30,000 XOF
730
+ * confirmation: true
731
+ * });
732
+ * ```
733
+ */
734
+ async create(payment) {
735
+ const txId = payment.txId ?? `PAY-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
736
+ const payeurAlias = payment.payeurAlias ?? payment.comptePayeur;
737
+ if (!payeurAlias) {
738
+ throw new Error("payeurAlias or comptePayeur is required for SPI payouts");
739
+ }
740
+ return this.request("POST", "/paiements", {
741
+ txId,
742
+ payeurAlias,
743
+ payeAlias: payment.payeAlias,
744
+ montant: payment.montant,
745
+ motif: payment.motif,
746
+ confirmation: payment.confirmation ?? false
747
+ });
748
+ }
749
+ /**
750
+ * Get payment details by transaction ID
751
+ *
752
+ * @param txId - Transaction ID
753
+ * @returns Payment details including status and history
754
+ * @throws {PiSpiNotFoundError} If payment not found
755
+ *
756
+ * @example
757
+ * ```typescript
758
+ * const payment = await sdk.paiements.get('23552722');
759
+ * console.log('Status:', payment.statut); // 'IRREVOCABLE'
760
+ * console.log('Amount:', payment.montant); // 150000
761
+ * ```
762
+ */
763
+ async get(txId) {
764
+ return this.request("GET", `/paiements/${encodeURIComponent(txId)}`);
765
+ }
766
+ /**
767
+ * List payments with filtering and pagination
768
+ *
769
+ * **Filter Options:**
770
+ * - Filter by account: `comptePayeur`
771
+ * - Filter by status: `statut` (INITIE, ENVOYE, IRREVOCABLE, REJETE)
772
+ * - Filter by dates: `dateEnvoi`, `dateIrrevocabilite`
773
+ * - Use QueryBuilder for advanced filtering
774
+ *
775
+ * @param params - Query parameters for filtering and pagination
776
+ * @returns Paginated list of payments
777
+ *
778
+ * @example
779
+ * ```typescript
780
+ * // List all payments for an account
781
+ * const payments = await sdk.paiements.list({
782
+ * comptePayeur: 'CIC2344256727788288822',
783
+ * page: 1,
784
+ * size: 20
785
+ * });
786
+ *
787
+ * // Filter by status
788
+ * const completed = await sdk.paiements.list({
789
+ * comptePayeur: 'CIC2344256727788288822',
790
+ * statut: 'IRREVOCABLE'
791
+ * });
792
+ * ```
793
+ */
794
+ async list(params) {
795
+ return this.request("GET", "/paiements", void 0, params);
796
+ }
797
+ /**
798
+ * Confirm a payment that was created with confirmation: true
799
+ */
800
+ async confirm(txId, decision, body) {
801
+ return this.request(
802
+ "PUT",
803
+ `/paiements/${encodeURIComponent(txId)}/confirmations`,
804
+ { decision, ...body }
805
+ );
806
+ }
807
+ /**
808
+ * Verify payment status by end-to-end ID
809
+ */
810
+ async verifyStatus(end2endId) {
811
+ return this.request(
812
+ "GET",
813
+ `/paiements/${encodeURIComponent(end2endId)}/statuts`
814
+ );
815
+ }
816
+ };
817
+
818
+ // src/services/paiements-en-masse.ts
819
+ var PaiementsEnMasseService = class extends BaseService {
820
+ /**
821
+ * Create bulk payments
822
+ *
823
+ * **Bulk Processing:**
824
+ * - All transactions share the same `instructionId`
825
+ * - Each transaction needs unique `txId`
826
+ * - Transactions are processed in parallel
827
+ * - Failed transactions can be retried
828
+ *
829
+ * **Performance Considerations:**
830
+ * - Larger bulks take longer to process
831
+ * - May hit HTTP timeout for very large bulks
832
+ * - Recommended: 500-5,000 transactions per bulk
833
+ * - For >10,000 transactions, split into multiple bulks
834
+ *
835
+ * **Response Status:**
836
+ * - `INITIE`: Bulk created, awaiting confirmation
837
+ * - `ENVOYE`: Bulk sent, transactions processing
838
+ * - `IRREVOCABLE`: All transactions completed
839
+ * - `PARTIEL`: Some transactions succeeded, some failed
840
+ * - `REJETE`: Bulk rejected (validation failed)
841
+ *
842
+ * @param payment - Bulk payment creation data
843
+ * @param payment.comptePayeur - Payer account number
844
+ * @param payment.instructionId - Unique bulk instruction ID
845
+ * @param payment.transactions - Array of payment transactions
846
+ * @param payment.transactions[].txId - Unique transaction ID (must be unique within bulk)
847
+ * @param payment.transactions[].payeAlias - Payee alias (SHID, MCOD, or MBNO)
848
+ * @param payment.transactions[].montant - Amount in centimes
849
+ * @param payment.transactions[].motif - Payment reason/description
850
+ * @param payment.transactions[].refDocType - Reference document type (optional)
851
+ * @param payment.transactions[].refDocNumero - Reference document number (optional)
852
+ * @returns Bulk payment response with status and summary
853
+ * @throws {PiSpiValidationError} If bulk fails validation (e.g., duplicate txId, invalid alias)
854
+ * @throws {PiSpiError} If account blocked or insufficient funds
855
+ *
856
+ * @example
857
+ * ```typescript
858
+ * // Create bulk payment for salary disbursement
859
+ * await sdk.paiementsEnMasse.createBulk({
860
+ * comptePayeur: 'CIC2344256727788288822',
861
+ * instructionId: 'SALARY-2023-03',
862
+ * transactions: [
863
+ * {
864
+ * txId: 'SAL-001',
865
+ * payeAlias: '8b1b2499-3e50-435b-b757-ac7a83d8aa7f',
866
+ * montant: 500000, // 5,000 XOF
867
+ * motif: 'Salaire mars 2023'
868
+ * },
869
+ * {
870
+ * txId: 'SAL-002',
871
+ * payeAlias: '4r5ty499-3e50-435b-b757-ac7a83d67juio',
872
+ * montant: 750000, // 7,500 XOF
873
+ * motif: 'Salaire mars 2023'
874
+ * }
875
+ * ]
876
+ * });
877
+ * ```
878
+ */
879
+ async createBulk(payment) {
880
+ return this.request("POST", "/paiements-groupes", payment);
881
+ }
882
+ /**
883
+ * Get bulk payment details and status
884
+ *
885
+ * **Response Includes:**
886
+ * - Overall bulk status
887
+ * - Transaction counts (total, succeeded, failed)
888
+ * - Individual transaction statuses
889
+ * - Failed transaction details
890
+ *
891
+ * @param instructionId - Bulk instruction ID
892
+ * @returns Bulk payment details with transaction statuses
893
+ * @throws {PiSpiNotFoundError} If bulk payment not found
894
+ *
895
+ * @example
896
+ * ```typescript
897
+ * const bulk = await sdk.paiementsEnMasse.get('SALARY-2023-03');
898
+ * console.log('Status:', bulk.statut); // 'IRREVOCABLE'
899
+ * console.log('Succeeded:', bulk.nombreSuccess); // 98
900
+ * console.log('Failed:', bulk.nombreEchec); // 2
901
+ * ```
902
+ */
903
+ async get(instructionId) {
904
+ return this.request(
905
+ "GET",
906
+ `/paiements-groupes/${encodeURIComponent(instructionId)}`
907
+ );
908
+ }
909
+ /**
910
+ * Confirm or retry a bulk payment
911
+ */
912
+ async confirm(instructionId, decision = true) {
913
+ return this.request(
914
+ "PUT",
915
+ `/paiements-groupes/${encodeURIComponent(instructionId)}/confirmations`,
916
+ { decision }
917
+ );
918
+ }
919
+ /**
920
+ * Retry failed payments in a bulk payment
921
+ *
922
+ * **Retry Process:**
923
+ * - Only failed transactions are retried
924
+ * - Successful transactions are not affected
925
+ * - Uses same `instructionId`
926
+ * - Can retry multiple times if needed
927
+ *
928
+ * @param instructionId - Bulk instruction ID
929
+ * @returns Retry response with updated status
930
+ * @throws {PiSpiNotFoundError} If bulk payment not found
931
+ * @throws {PiSpiError} If no failed transactions to retry
932
+ *
933
+ * @example
934
+ * ```typescript
935
+ * // Retry failed transactions
936
+ * await sdk.paiementsEnMasse.retry('SALARY-2023-03');
937
+ * ```
938
+ */
939
+ async retry(instructionId) {
940
+ return this.confirm(instructionId, true);
941
+ }
942
+ };
943
+
944
+ // src/services/retours-fonds.ts
945
+ var RetoursFondsService = class extends BaseService {
946
+ /**
947
+ * Create a fund return
948
+ *
949
+ * **Return Process:**
950
+ * 1. Business identifies original payment transaction
951
+ * 2. Creates return request (must be within 90 days)
952
+ * 3. Return is processed immediately
953
+ * 4. Funds are returned to original payer
954
+ *
955
+ * **Status Values:**
956
+ * - `ENVOYE`: Return sent successfully
957
+ * - `IRREVOCABLE`: Return confirmed and cannot be reversed
958
+ * - `REJETE`: Return rejected (check `statutRaison` for error code)
959
+ *
960
+ * **Rejection Reasons:**
961
+ * - `AM04`: Insufficient guarantee funds
962
+ * - `AM09`: Wrong amount
963
+ * - `AC06`: Blocked account
964
+ * - `FR01`: Fraud suspicion
965
+ * - `RR04`: Regulatory reason
966
+ *
967
+ * @param returnRequest - Fund return request data
968
+ * @param returnRequest.comptePaye - Business account number (original payee)
969
+ * @param returnRequest.txId - Original payment transaction ID
970
+ * @param returnRequest.montant - Amount to return in centimes (e.g., 150000 = 1,500 XOF)
971
+ * @param returnRequest.motif - Return reason code (e.g., 'CUST' for customer request)
972
+ * @returns Fund return response
973
+ * @throws {PiSpiValidationError} If return fails validation (e.g., > 90 days, invalid txId)
974
+ * @throws {PiSpiError} If account blocked or insufficient funds
975
+ *
976
+ * @example
977
+ * ```typescript
978
+ * // Return full payment amount
979
+ * await sdk.retoursFonds.create({
980
+ * comptePaye: 'CIC2344256727788288822',
981
+ * txId: '23552722', // Original payment ID
982
+ * montant: 150000, // 1,500 XOF
983
+ * motif: 'CUST' // Customer request
984
+ * });
985
+ * ```
986
+ */
987
+ async create(returnRequest) {
988
+ const end2endId = returnRequest.end2endId ?? returnRequest.txId;
989
+ if (!end2endId) {
990
+ throw new Error("end2endId or txId is required for fund returns");
991
+ }
992
+ return this.request(
993
+ "PUT",
994
+ `/paiements/${encodeURIComponent(end2endId)}/retours`
995
+ );
996
+ }
997
+ /**
998
+ * Get fund return details by end-to-end ID
999
+ */
1000
+ async get(end2endId) {
1001
+ return this.request(
1002
+ "GET",
1003
+ `/paiements/${encodeURIComponent(end2endId)}/statuts`
1004
+ );
1005
+ }
1006
+ /**
1007
+ * List payments with fund return status filter
1008
+ */
1009
+ async list(params) {
1010
+ return this.request("GET", "/paiements", void 0, params);
1011
+ }
1012
+ };
1013
+
1014
+ // src/services/demandes-annulation.ts
1015
+ var DemandesAnnulationService = class extends BaseService {
1016
+ /**
1017
+ * Create a cancellation request
1018
+ *
1019
+ * **Cancellation Process:**
1020
+ * 1. Business identifies payment to cancel
1021
+ * 2. Creates cancellation request (must be within 90 days)
1022
+ * 3. Payee receives cancellation request
1023
+ * 4. Payee accepts or rejects
1024
+ * 5. If accepted, funds are returned via fund return mechanism
1025
+ *
1026
+ * **Status Values:**
1027
+ * - `INITIE`: Cancellation request sent, awaiting payee response
1028
+ * - `ACCEPTE`: Payee accepted cancellation (funds returned)
1029
+ * - `REJETE`: Payee rejected cancellation request
1030
+ *
1031
+ * **Rejection Reasons:**
1032
+ * - `CUST`: Customer rejection (payee refuses cancellation)
1033
+ * - `AM09`: Wrong amount
1034
+ * - `AC06`: Blocked account
1035
+ * - `FR01`: Fraud suspicion
1036
+ *
1037
+ * @param request - Cancellation request data
1038
+ * @param request.comptePayeur - Business account number (original payer)
1039
+ * @param request.txId - Original payment transaction ID to cancel
1040
+ * @param request.motif - Cancellation reason code (e.g., 'CUST' for customer request)
1041
+ * @returns Cancellation request response
1042
+ * @throws {PiSpiValidationError} If cancellation fails validation (e.g., > 90 days, invalid txId)
1043
+ * @throws {PiSpiNotFoundError} If payment not found
1044
+ *
1045
+ * @example
1046
+ * ```typescript
1047
+ * // Request cancellation
1048
+ * await sdk.demandesAnnulation.create({
1049
+ * comptePayeur: 'CIC2344256727788288822',
1050
+ * txId: '23552722', // Payment to cancel
1051
+ * motif: 'CUST' // Customer request
1052
+ * });
1053
+ * ```
1054
+ */
1055
+ async create(request) {
1056
+ const end2endId = request.end2endId ?? request.txId;
1057
+ if (!end2endId) {
1058
+ throw new Error("end2endId or txId is required for cancellation requests");
1059
+ }
1060
+ return this.request(
1061
+ "POST",
1062
+ `/paiements/${encodeURIComponent(end2endId)}/annulations`,
1063
+ { raison: request.motif }
1064
+ );
1065
+ }
1066
+ /**
1067
+ * Get cancellation request details by end-to-end ID
1068
+ */
1069
+ async get(end2endId) {
1070
+ return this.request(
1071
+ "GET",
1072
+ `/paiements/${encodeURIComponent(end2endId)}/statuts`
1073
+ );
1074
+ }
1075
+ /**
1076
+ * List payments with cancellation status filter
1077
+ */
1078
+ async list(params) {
1079
+ return this.request("GET", "/paiements", void 0, params);
1080
+ }
1081
+ /**
1082
+ * Respond to a cancellation request (accept or reject)
1083
+ */
1084
+ async respond(end2endId, decision) {
1085
+ return this.request(
1086
+ "PUT",
1087
+ `/paiements/${encodeURIComponent(end2endId)}/annulations/reponses`,
1088
+ { decision }
1089
+ );
1090
+ }
1091
+ };
1092
+
1093
+ // src/qrcode/logo.ts
1094
+ var AMBER_LOGO_SEGMENTS = [
1095
+ "iVBORw0KGgoAAAANSUhEUgAAAMAAAADACAMAAABlApw1AAACUlBMVEUAAAD7uQD7uQD7uQD7uQD7uQD7",
1096
+ "uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7",
1097
+ "uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7",
1098
+ "uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7",
1099
+ "uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7",
1100
+ "uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7",
1101
+ "uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7",
1102
+ "uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7",
1103
+ "uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7",
1104
+ "uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7",
1105
+ "uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQD7uQBqFsbfAAAAxXRSTlMAAAUpaqDF2uPq7ezn",
1106
+ "4djPzsvDwsC3trCdfVEdAgtJn977/vXUlUQIQK7087FHHJ7vKBmsLBqtyi8bMC3WuSs+v9EjvLM0ILW9",
1107
+ "zR4yxh8Xphb9shil+Ov8bzND4BUh14g3pKgmmQdL+YsO7j8PupYKVSVKaKI15cETLnpkca+n08QN5gOX",
1108
+ "XV5gTV9TbooU0HTdQYmOewaMIk8E6PZc0tyakN9CTPJaZcgBRngJJDs4gEhY8E5SEpwREGHi5JuU2/dw",
1109
+ "ofG+YwjdAcYAAAZRSURBVHja7Z37XxRVGIfnhULYFQQlNJTLriGiSSiBGGFihVwqm0BJMfOGS2aE5C2z",
1110
+ "q0ghGqXdyBQrIaKbUWSl2fX8X82wrCyX2Xln59zm8znfn4fZ59nznrOzh3POalqcgYTEO+5MmpNsJsXn",
1111
+ "nxbf3OTJpM6ZSNq89PFkzF9gJvOuLCMLF92dvXgJxMsRL35Obl5+gNBJcOk9BctygKMDFC4vWkGJfiIr",
1112
+ "713FTwGK7yuhiz+uULSakwGsKaWPb2bB/VwMoKycDT8hays4GDDk52LAlJ+9AcA6pvyGwQNMDaAyM8hW",
1113
+ "gDy4jKEBlFUxxjcybz0zA8b1H8n8REYGnPiZGXDjZ2TAkZ+FAUBlFevxJzoZD1E2gOINHPGNVNMdi7jW",
1114
+ "TzhUq0gAv2FA7+laCD8hGzZSMhDET8jDVAwAEh/hOf5EJ/NRCgZQkyQI30i1+54srH7CcV1FgvldGwjn",
1115
+ "d2fA/vsXWwNj/Nkkmt5MbZxPFQZ/nWj2cNLjGosA6rNEk0eSVe/cwOCXon7C2eTYQC5+5way8Ts1ANgo",
1116
+ "Gb9h4GA0BajIEM07MxnoWUejfjjMXzlPVT1OQL76j2RhGcZAXn5CyhEGMvNjDABqJOY3DNbF7skADY+J",
1117
+ "ZoyZYGYlxOR/nPP8lfNUxagiues/Eut+4A1+awOv8BsGT4Cn+Ulw85MwC3+D9P33dvSnZsybgtD5K+ep",
1118
+ "agSv1k84waYpVeQ5/mkGTviDW0q28omvGW2A5/cXPb1qWwWXVG5vsWuDHRMG8AySf+ezuwq5rQuDNWk2",
1119
+ "OPrucE+GnD0o/EDTXq7L2mwFCNnXCmYH2L8Swx9qe47rykKMwIHnTYGDL6AaoD2H78pIjAApfxE06NiC",
1120
+ "4U87xHllJ0pgRSdohagVfIGXeNY/WoAcTtCOHMUIHDvOfWktSiD1Ze2EjrhOf4V3AyAFmk9qr2Ia4Ggi",
1121
+ "b36kAHlNex1z2RtvyiqQrr2F8jwlq0Cy5sNc1sW9C2AF/Jofc1k7d34loASUgBJQAkpACSgBeQRqT3ff",
1122
+ "ztvbLGyg9Z2ebkR61lvdIOfM5A1O986lKECCkyFnrV7/3LvR11mG9FndoL5lygvRFIhOWwwBVKwFUh3D",
1123
+ "KAEloASUgBJQAkpACSgBJaAElIASUAJKQAkoASWgBJSAElACSkAJKAFXAsXveVygtcnbAhoklqPWcUsr",
1124
+ "oEHO+33n28K5gKonIQIfoLYFf4ja1SBE4CPMGkiZBXZjzjiWWeAYZiuCzAItH3tcIPSJxwWMOyA298ss",
1125
+ "sBaxnUJqgaW5Hhcgef22BnILfLrL4wKk1PajAC2A2gBBXeDiZ3YDEVogRYgAuWS3sQ4tcFmMABlIABoC",
1126
+ "yVqmIIGSDptTUnACddoVQQLk8y9iGiAFNmtfXhUkQFoGY23uwgmEhrQdX4kSIL7eVnApkL9agxPCBMjF",
1127
+ "K42WZYQTyOvXYK/TcYieAAnWNgyDC4GrX4MGMILZz8pGwOgIIxZnNqEE9nxj7klffEmgANGr+76drTNj",
1128
+ "BPzfmX8IsN/ZlKSlwPF4BAyF/KaT35/rn9YQCIHQD+EPQ4Bs1K7uSEqvdc6a3B/z4xIwEhytLj3fO5gd",
1129
+ "fbef7E4b1AsiT4QAPzsxaA5ZxeX51Hpgyt1suqa+aGzybBJnBlIkmt+LBlP5TYMzzp+rJeI3DJYMoTbd",
1130
+ "yBH98Mx5DS9V0cz331sGs/N7x8CK3ysG1vzjBtL35OYY/KbB0FbRhDb8v1yP/VV6WO4qChT8ajcdI3U/",
1131
+ "CBQctJ+TlNgAwy+zAY5fXgMsv2nw2wHRtDOjD+DPiYNTHdK1QaD9OppfxirC14+cBk75ZTNwzi+XQTz8",
1132
+ "psHgqGjycPSu+M6phIRBKdog0DUWF78sVRRf/chj4IZfBgN3/OIN3PKbBh0Cn4v0Avfn5EJ/z+/C3v8B",
1133
+ "J88/1m3Q6XxJMx1+1/Uj1oAWvygDevxiDGjyj/8fjfOMF11+c76o+wZX/pt28z9yVxHt95+3AQt+ngZs",
1134
+ "+PkZsOIfN0j2Mr9p0M18NG2+yY7fHE0drquI4/2nPX5ObwO2/YBl/fAwYM/P1iDwB3t+0+DaLTb8f57l",
1135
+ "c8g+wPb0AAP+lBFev3ID0PjXTtq/XT/695EETvymwnBNX9I/9OhDl/ctb+WHH26FsdwL/95K8fld50Zd",
1136
+ "03+H7Ld0WOR/rIwlUtPE/X8AAAAASUVORK5CYII="
1137
+ ];
1138
+ var OCTO_QRCODE_LOGO_SEGMENTS = [
1139
+ "iVBORw0KGgoAAAANSUhEUgAAAPYAAAD6CAYAAACS0LqzAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAA",
1140
+ "AAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAA9qADAAQAAAABAAAA+gAA",
1141
+ "AAA4bIViAAAVTklEQVR4Ae2dW2xcx3nHZ5bcpVYXmEEkBPYDuXmI5ASoJVVGEyCwRD4YsFE5lquXpK0Q",
1142
+ "CYUvDwYiG0iARkEkAbGLGkVsoyrgSwNLdYq4LRQ7qQEH9YNoGQGSoJIYP0ixXrr0g51ADkJDIpdcUns6",
1143
+ "H9cUd8nl7jln5/LNzH8AWrvnMueb3zc/z+w5Z89KgZKaQFKrVRbEzTE5UNjZaIiKFGLXqp0rq94zeptM",
1144
+ "CyHVn/ZS1VVjIsS0lCsxSplM31xsTA3IgcliuTyh6zgx1KP6Jko3AkmSDM/XZg4XCoUH1XZj3bbFOuME",
1145
+ "JkTSOFPcsOmN1v8BGD+qhweA2OskjYRerM99K0kaR9VIN7zOZljshkBVyGSi2CiclOVy1U0IvI8KsTvk",
1146
+ "Z3F+5kAjEa9A6A5weC2qNoR4fsOGjc/xCst9NBC7JQc0Si/UZ58ViTzcshgv+ROYKCbyCEbvlURB7E9Z",
1147
+ "1NSJsYFC8rpI1pwQW6GFV5wJVEVh8KFSqTTJOUhbsUFsRXpJapmcUy8rtsDjOAYISDEt5OA45FYfIg3g",
1148
+ "9apKSO1VunoHC7mXGEUtNqTu7YmXW0DueEdsSO2lsumDjlzuKEdsSJ3eD6+3jFju6MSG1F6rmif4qroU",
1149
+ "Nh7bpbCoxF66Tj1fu6R6RyVPD8E+3hKITu6Ct6nKGHjz5pMaLmll5BbI5pUFdTmTvsQTSHt6NiOKEfuW",
1150
+ "1Lj5pGeHCHyDaEbu4MWG1IGrmr15UcgdtNiQOnuvj2SP4OUOVmxIHYmi+ZsZtNxBig2p8/f2yPYMVu7g",
1151
+ "xIbUkanZf3ODlDs4sevzs5fw1cv+e3tkNQQnd1DXsevzM69A6siU1NPc4K5zBzNiN6XGk0/09PNoawlm",
1152
+ "5A5CbEgdrYgmGl4tDpV3+/4UVO+n4pDaRN+Ous7KQr12jk7C+kzB6xEbUvvc9ZjHLsVksVQe93Xk9lZs",
1153
+ "blLPXJ8WVy68u/R37fdTYurqe0s9d/b6J4LWcSnb7hjVHsq227PXue32ETGyfaeobL9LfHHPPdpj0lKh",
1154
+ "x3J7KTYnqa9cOC/eeu1floTmJLCWjm2pkk1bhsWefQ+Ig498V+T5n4TRMD2V2zuxF+Zmn02EOGo0mSkq",
1155
+ "v/bRlHjx5KPishIbRR+BvfsP8RPcQ7m9EnthvnZcndQ4oa8b5avprddOiZ++9DSrKXa+lvDd6+Ajx8TB",
1156
+ "h4/xCdAzub0Rm4vUZ19+Spx96Sk+HS7gSO4ee0A8+v0XBU3VWRSZnC4NbTrCIpYeQXghNqTukcWAV4+q",
1157
+ "k2vfe+EXkDtjjtmLDakzZjTAzSF39qSyFhtSZ09oqHtA7myZZSs2pM6WyBi2htzps8xSbEidPoGxbQm5",
1158
+ "02Wc3b3ikDpd4mLdiu7o+8Fj9/G51Kh+S72u7q3glg9WYkNqbt2DZzzs5FY3TFHf5USLzVQcUnPqFn7E",
1159
+ "wm1arr4wckJ95fMkB3osxIbUHLqCnzFA7s55cy42pO6cGCxNTwByr2XlVGxIvTYhWJKPAORu5+ZMbEjd",
1160
+ "ngi8658A5F5h6ERsSL2SALzSSwByN3laF7s+N/ctIRrP6U1n9trwLa3szHzZA3ILYVXsxXr9m43G4mnX",
1161
+ "HQRSu86A+ePHLrc1sSG1+c6MI7QTiFluK2JD6vYOh3f2CMQqt3GxIbW9TowjdSZAcv/Dv/+q80oHS23c",
1162
+ "oWb0XnEuUr/6w+/gcUYOOjCXQ9K95fTgSS6FnttHbpiMx9iIzUXqF1RCz7/5qkmGqNsTAvvUE1AfPf4i",
1163
+ "m2gLhcHDg6XSGRMBGREbUptIFerUQSAWubWLvVCrjSUyOacjCf3UgZG6H3ph7xuD3Fo/Y9dv3NiVyMbr",
1164
+ "rrsFpHadAd7Hf0d9NOP0mZvu7dD9mVvbiE1Si0GpRmrp9CHQkJq3VJyiC3nk1iI2pObUXRFLFgLc5JaJ",
1165
+ "HC+WyxNZ2tBp276n4pC6E1Ys84UAt2l5Ukher9fru/rl19eIDan7xY/9uRBgNXJLMS3k4HipVJrMyye3",
1166
+ "2JA6L3Lsx5VASHLnEhtSc+2aiKtfAqHInVnsWq1WGZCNSzj73W8Xwv5cCYQgd6aTZ02p6eYTXNLi2ikR",
1167
+ "V/8EWJ1QS8SwSBbPZT2hlnrEXpFaVPpHl78GXKfOzw57ZiPAauQWolpUl8JkuVxN04pUYkPqNCixTYgE",
1168
+ "fJW7p9iQOsTuijZlIeCj3F3FhtRZ0o9tQybgm9zrig2pQ+6maFseAj7J3VFsSJ0n7dgnBgK+yL1GbEgd",
1169
+ "Q/dEG/shwE7uofJu9Ry16dY2rbmOXZCNZ9UGldaNbL/GJS3bxHG8LARYXedWri7UZ8nZttImNv1KhxTy",
1170
+ "QNsWlt9AasvAcbhcBFjJncjDi/Mzbd7emopzmIJD6lx9DDs5JMBmWq6+EVYslT+/PCW/NWIPFBrHFZ+K",
1171
+ "K0aQ2hV5HLcfAmxGbnXraX1u9uhyW5ZG7E9H6/9bXmj7X0htmziOp5sAi5G7ZdReGrEHxM0x3Q1NWx+k",
1172
+ "TksK23EmwGLkVqP2/HztMHFqTsVlgabh1gukto4cBzRIgIPcSugHqYnS1TQcUhvsYajaKQHX0/LiUPkz",
1173
+ "BRfTcEjttN/h4IYJuB65F+ZmDhREQe4z3M626iF1Gw68CZSAU7ml2DUokkJFiMQKXl+k3rhBiK/uFGLk",
1174
+ "c0LcOSJEWb2nZSj+EPjle0L86Odu4yW5qdj+IcBGQ1YGldSVpaMb/s/Zl59i/6uXW4fVmYe9QuzeDpEN",
1175
+ "d4doqie5t94xIg4+fMxamwsFuVOJbf6mFJL67EtPWWtYngPd+2Ul9T0QOg877NOdAPX9jVtuE/d//fHu",
1176
+ "G+pbW7l155m+OttruvbRFHupaZT+xr2Quj1zeKeTAMlNLtgqxsXm9KuGnaCS1PSHAgImCcxe/8TqL3wa",
1177
+ "FfvKhfPisvrjWugEGaTmmp3w4iIXLl9410rDjIp99uWnrTQiz0GWTpSpz9QoIGCTwFuvnbJyOGNi0+cJ",
1178
+ "zqM1jdQkNwoI2CRAs9iZ69PGD2lM7CuWphx5CNE1abqkhQICtgnQZ+0LE28aP6wxsf934r+NB5/3ALt3",
1179
+ "4Ax4XnbYr38CU1fV3TOGizGxP/7oA8Oh56/+ztH8+2JPEOiXwOWL5k+gGRPb5jW7rKC33pZ1D2wPAvoI",
1180
+ "zPr8GdvGCYK8qCF2XnLYTwcBG4OesRFbBwDUAQIgkI8AxM7HDXuBAGsCEJt1ehAcCOQjALHzccNeIMCa",
1181
+ "AMRmnR4EBwL5CEDsfNywFwiwJgCxWacHwYFAPgIQOx837AUCrAlAbNbpQXAgkI8AxM7HDXuBAGsCEJt1",
1182
+ "ehAcCOQjALHzccNeIMCaAMRmnR4EBwL5CNBzxaMrF69mf9DCZ9VXPW19j/vS+0LMzvNOy44Re4+Wol/1",
1183
+ "yFp+Z+9Jv1lDs7J9lGL/5H+ys/3qXfbEfvs3QnDvmH/3NXtiu/6pnuy9xf0emIq7zwEiAAHtBCC2dqSo",
1184
+ "EATcE4DY7nOACEBAOwGIrR0pKgQB9wQgtvscIAIQ0E4AYmtHigpBwD0BiO0+B4gABLQTgNjakaJCEHBP",
1185
+ "AGK7zwEiAAHtBCC2dqSoEATcE4DY7nOACEBAOwGIrR0pKgQB9wQgtvscIAIQ0E4AYmtHigpBwD0BiO0+",
1186
+ "B4gABLQTgNjakaJCEHBPAGK7zwEiAAHtBCC2dqSoEATcE4DY7nOACEBAOwGIrR0pKgQB9wQgtvscIAIQ",
1187
+ "0E4AYmtHigpBwD0BiO0+B4gABLQTgNjakaJCEHBPAGK7zwEiAAHtBCC2dqSoEATcE4DY7nOACEBAOwGI",
1188
+ "rR0pKgQB9wQgtvscIAIQ0E4AYmtHigpBwD0BiO0+B4gABLQTgNjakaJCEHBPAGK7zwEiAAHtBCC2dqSo",
1189
+ "EATcE4DY7nOACEBAOwGIrR0pKgQB9wQgtvscIAIQ0E4AYmtHigpBwD0BiO0+B4gABLQTgNjakaJCEHBP",
1190
+ "AGK7zwEiAAHtBCC2dqSoEATcE4DY7nOACEBAOwGIrR0pKgQB9wQgtvscIIIeBDZu6LEBVq8hALHXIMECbgQe3MstIv7xDPIPERHG",
1191
+ "TuDev2gSePs3Qnw8HTuNdO2H2Ok4YSvHBEhu+nt/Kl0gs3NC/PN/pds2xK0gdohZDbhNO0bTNS72kR2f",
1192
+ "sdP1E2y1ikDs4qzCwe4txGaXEj8Cgti88wSxeeeHbXR//IRtaAhMEYDY6Aa5CHzwh1y7YSdLBCC2JdCh",
1193
+ "HYbOOv8Rl57YphVis00N/8AuXuUfY6wRQuxYM6+h3Zfe11AJqjBCAGIbwRpHpb9TN4vQlByFHwGIzS8n",
1194
+ "XkVEt3mi8CMAsfnlxKuISGyM2vxSBrH55cSriEhqjNr8Ugax+eXEu4gwavNLGcTmlxPvIqJR+2fvehd2",
1195
+ "0AEbE3vTluGgwaFx7QTe/rUQdJYchQcBY2Jv3HIbjxYiCmsETqnvP+PLIb1xb7s95XdPe1e17hbGxB79",
1196
+ "wl3rHhQrwiRAU/Jnfoyz5L2yu+0Oj8X+4p57erUP6wMkQCM25O6eWBuDnrER+0sQu3t2A177we8hd7f0",
1197
+ "3mnBDWNij27fKb60B4+X7JbgkNeR3Cf+FZ+5O+XYxqBnTGxq0J59+zu1C8siIbA8Lce3wFYSvnf/3wob",
1198
+ "V4yMir1v/yFh40TBCja84kaA5D71n0L85G2M3pSbg48cs5IiJXZi7OvydMnr0BPPWGkIDsKbAF3nppNq",
1199
+ "v3yPd5wmo6PR2salLmqDElsaE5sOcPfYA0t/9BolbgI0ev/o50J851RTcHofSyGhbY3Wiml1UEoxmSSi",
1200
+ "YhLwY99/Sfz91a+Iax/i1iSTnH2pe1lwivfPdwixW/3tGBFi67AvLcge56En/9HaaK2iqw7evCneKRTE",
1201
+ "geyhpt+DpuTfe+EX4geP3eet3B+rp3LamkbG9DXIi+opLPRHhcQe+ZwQn1X/blU3LvbzY3ycGB58+Jia",
1202
+ "tX6t2Ugr/238Vi7UamOJTM7ZON61j6a8ltsGIxwjLAIktcUpeBNeIo9IelWfm/mT+qxtZSIEucPquGjN",
1203
+ "+gScSK3CKSby883LXY3kzPrh6V1DJxFoWo7LYHq5ojZeBFxJra5yTcpyuboktpQDb9jEArlt0saxbBNw",
1204
+ "J7VqaVJ4ntq7JHaxXJ5QU3H1Z69AbnuscSR7BJxKrZpZFGKCWtuciqsXMhEnaYHNArlt0saxTBNwLbWQ",
1205
+ "8jRNw6mdt8SmUTsRwuqUnAKA3EQBxXcCzqVW166LjZXB+ZbYBLY0NH9E/VOl1zYL5LZJG8fSTYCB1Oqz",
1206
+ "tTy5PFpT+9rElvIz01JdA9Pd8DT1Qe40lLANNwIspFZT8FK5fLqVTZvYtKJ5Ik080bqRrdeQ2xZpHEcH",
1207
+ "ARZSr5qCL7drjdi0orRh43NJklg/mUbHhtxEAYU7ATZSJ3K8dQq+zE0uv+j073xt5oSU8nindaaX4Q41",
1208
+ "04RRf14C3KWmdnUVmzaA3EQBBQSaBHyQmiLtKTZtBLmJAkrsBHyRmvKUSmzaEHITBZRYCfCQOpkuJoXd",
1209
+ "nT5Tr85Lx5Nnqzei90PlTSdwQq0TGSwLnQAXqcVi0vFEWSf+qUfs5Z0xci+TwL8xEOAkdWnz5sm0zDOL",
1210
+ "TRVD7rR4sZ3PBHyVmpjnEpt2hNxEASVUAj5LTTnJLTbtDLmJAkrsBHyRmvKUSmzaEHITBZRYCfCQOpkuJoXd",
1211
+ "AMXmnJLTbtDLmJAkpoBHyXmvLRl9hUwXztxmkpC9+k17YLr3LaJmz8e",
1212
+ "pG4ytvoZe3Va6TP3TfUTJWp5dfU6G+9xQs0GZXvHgNQrrJ2O2Mth1Gq1yoBM1B1qGLmXmeDfbAQgdTsv",
1213
+ "FmJTSJC7PTF4l54ApF7Lio3YFBrkXpsgLOlOAFJ35sNKbAoRcndOFJauJQCp1zJZXsJObAoMci+nB/+u",
1214
+ "RwBSr0emuZyl2BQa5O6euJjXQure2WcrNoUOuXsnMLYtIHW6jLMWm5oAudMlMoatDj35jLj/G487byrd",
1215
+ "++3iNtEsDWcvNjUGcmdJaZjbPnb8RbF3/yHnjfNBaoLkhdgUKOQmCnEWSJ09796ITU2D3NkT7PsekDpf",
1216
+ "Bl0Sm5roWu7Z65+If/vht8X5N3+cjzj2SkWA7uN/8p/+Q4xuvyvV9iY38mX63crAO7EpeNdyUwzvvPmq",
1217
+ "+OnLT4trH07RWxSNBO7/+uPirx75rti0ZVhjrfmq8lFqaqmXYlPgHOSmOCA4Uei/kMR7//JvxH1//big",
1218
+ "0ZpDod+io5+t4hBL1hi8FZsaWr9xY5cYlPTccuf/a5+6+p64fOG8uHLxXfHxhx8I+q73zPXprPmIZvtt",
1219
+ "d4wuCTz6hT8Td489IEbUlJvDCL2cAJ+lpjZ4LTY1gJPcFA+K/wR8l5oy4L3Y1AjITRRQdBAIQWriEITY",
1220
+ "1BDITRRQ+iEQitTEIBixqTGQmyig5CEQktTU/qDEpgZBbqKAkoVAaFJT24MTmxoFuYkCShoCIUpN7Q5S",
1221
+ "bGoY5CYKKN0IhCo1tTlYsalx9VrtsJDJK/QaBQTaCEgxWSyVx6WUQd5sELTYlEjI3dad8YYIBC51s4kR",
1222
+ "pBpyR5DktE2MQOpoxKaGQu60PT/g7SKRmjIY/FS8tZtC7lYakb2OSGrKbFRiU4MhN1GIrEQmNWU3OrGp",
1223
+ "0ZCbKERSIpSaMhul2NRwyE0UAi+RSk1Zdfozui67ValcPk1Px3AZA45tkEDEUhPVaMWmxtOzoSE3kQiu",
1224
+ "VIsN+VCoN5+kyVa0U/FWOPO1mROqExxvXYbX3hKoFhM5Lsvlqrct0BA4xP4UYn1u9qh6+awGpqjCFYHI",
1225
+ "p9+t2KOeireCKG3Y+JxYbOxWy6qty/HaFwKN50O+9ztrFiB2C7HS5s2TN9U0Tn3uPtOyGC9ZE0imC3Lg",
1226
+ "odKGzUdj/ky9OkWYiq8m8un7hVptLJENNTWXu9bZBIudEkimk0Q8TzMtCL02ERB7LZO2JSR4QzQOSyke",
1227
+ "VJIPt63EGxcEJtSM6h0I3R09xO7Op21tcxRPDijBdwrRIMkrkL0Nke43VSGSaSELk42byW+HpHwj9rPd",
1228
+ "aQH/P0RzGOBNa7tyAAAAAElFTkSuQmCC"
1229
+ ];
1230
+ var PISPI_AMBER_LOGO_DATA_URL = `data:image/png;base64,${AMBER_LOGO_SEGMENTS.join("")}`;
1231
+ var PISPI_QRCODE_LOGO_DATA_URL = `data:image/png;base64,${OCTO_QRCODE_LOGO_SEGMENTS.join("")}`;
1232
+ var DEFAULT_PISPI_LOGO_DATA_URL = PISPI_QRCODE_LOGO_DATA_URL;
1233
+
1234
+ // src/qrcode/index.ts
1235
+ var cachedQrCodeModule = null;
1236
+ function resolveQrCodeModule(module) {
1237
+ if (module?.create) {
1238
+ return module;
1239
+ }
1240
+ if (module?.default?.create) {
1241
+ return module.default;
1242
+ }
1243
+ throw new Error(`Le module "qrcode" n'expose pas l'API attendue.`);
1244
+ }
1245
+ async function getQrCodeModule() {
1246
+ if (cachedQrCodeModule) {
1247
+ return cachedQrCodeModule;
1248
+ }
1249
+ if (typeof window !== "undefined" && window.QRCode) {
1250
+ const resolved2 = resolveQrCodeModule(window.QRCode);
1251
+ cachedQrCodeModule = resolved2;
1252
+ return resolved2;
1253
+ }
1254
+ const module = await import("qrcode");
1255
+ const resolved = resolveQrCodeModule(module);
1256
+ cachedQrCodeModule = resolved;
1257
+ return resolved;
1258
+ }
1259
+ var DEFAULT_MERCHANT_CATEGORY_CODE = "0000";
1260
+ var DEFAULT_CURRENCY = "952";
1261
+ var DEFAULT_MERCHANT_NAME = "X";
1262
+ var DEFAULT_MERCHANT_CITY = "X";
1263
+ var DEFAULT_REFERENCE_LABEL_TAG = "05";
1264
+ var DEFAULT_MERCHANT_CHANNEL_TAG = "11";
1265
+ var DEFAULT_LOGO_SIZE_RATIO = 0.18;
1266
+ var DEFAULT_LOGO_PADDING_RATIO = 0;
1267
+ var DEFAULT_LOGO_BORDER_RADIUS_RATIO = 0.5;
1268
+ var DEFAULT_MARGIN = 0;
1269
+ var DEFAULT_SVG_SIZE = 400;
1270
+ var DEFAULT_DOT_COLOR = "#1A1A1A";
1271
+ var DEFAULT_BACKGROUND_COLOR = "#FFFFFF";
1272
+ var DOT_RADIUS_RATIO = 0.44;
1273
+ var FINDER_CORNER_RADIUS = 0.8;
1274
+ function createQrPayload(input, options = {}) {
1275
+ const {
1276
+ alias,
1277
+ amount,
1278
+ countryCode,
1279
+ qrType,
1280
+ referenceLabel
1281
+ } = input;
1282
+ if (!alias) {
1283
+ throw new Error('Le param\xE8tre "alias" est obligatoire.');
1284
+ }
1285
+ validateAlias(alias);
1286
+ if (!countryCode) {
1287
+ throw new Error('Le param\xE8tre "countryCode" est obligatoire.');
1288
+ }
1289
+ validateCountryCode(countryCode);
1290
+ if (!qrType) {
1291
+ throw new Error('Le param\xE8tre "qrType" est obligatoire.');
1292
+ }
1293
+ if (!referenceLabel) {
1294
+ throw new Error('Le param\xE8tre "referenceLabel" est obligatoire.');
1295
+ }
1296
+ validateReferenceLabel(referenceLabel);
1297
+ if (amount !== void 0 && amount !== null && amount !== "") {
1298
+ validateAmount(amount);
1299
+ }
1300
+ const payloadSegments = [];
1301
+ payloadSegments.push(formatDataObject("00", "01"));
1302
+ const merchantAccountInformation = [
1303
+ formatDataObject("00", "int.bceao.pi"),
1304
+ formatDataObject("01", alias)
1305
+ ].join("");
1306
+ payloadSegments.push(
1307
+ formatDataObject("36", merchantAccountInformation),
1308
+ formatDataObject("52", DEFAULT_MERCHANT_CATEGORY_CODE),
1309
+ formatDataObject("53", DEFAULT_CURRENCY)
1310
+ );
1311
+ if (amount !== void 0 && amount !== null && amount !== "") {
1312
+ payloadSegments.push(
1313
+ formatDataObject("54", sanitizeAmount(amount))
1314
+ );
1315
+ }
1316
+ payloadSegments.push(
1317
+ formatDataObject("58", countryCode),
1318
+ formatDataObject("59", DEFAULT_MERCHANT_NAME),
1319
+ formatDataObject("60", DEFAULT_MERCHANT_CITY)
1320
+ );
1321
+ const normalizedQrType = normalizeQrType(qrType);
1322
+ const additionalData = buildAdditionalData(
1323
+ normalizedQrType,
1324
+ referenceLabel,
1325
+ options.additionalData
1326
+ );
1327
+ if (additionalData) {
1328
+ payloadSegments.push(formatDataObject("62", additionalData));
1329
+ }
1330
+ const payloadWithoutCrc = payloadSegments.join("");
1331
+ const crcInput = `${payloadWithoutCrc}6304`;
1332
+ const crc = computeCrc16(crcInput);
1333
+ return { payload: `${payloadWithoutCrc}6304${crc}` };
1334
+ }
1335
+ function buildAdditionalData(qrType, referenceLabel, overrides) {
1336
+ const segments = [];
1337
+ const referenceLabelTag = formatDataObject(
1338
+ DEFAULT_REFERENCE_LABEL_TAG,
1339
+ referenceLabel
1340
+ );
1341
+ segments.push(referenceLabelTag);
1342
+ const merchantChannelValue = mapMerchantChannelFromType(qrType);
1343
+ segments.push(
1344
+ formatDataObject(DEFAULT_MERCHANT_CHANNEL_TAG, merchantChannelValue)
1345
+ );
1346
+ if (overrides?.purposeOfTransaction) {
1347
+ segments.push(formatDataObject("12", overrides.purposeOfTransaction));
1348
+ }
1349
+ if (overrides?.custom) {
1350
+ const entries = Object.entries(overrides.custom).sort(
1351
+ ([a], [b]) => a.localeCompare(b)
1352
+ );
1353
+ for (const [tag, value] of entries) {
1354
+ validateSubTag(tag);
1355
+ segments.push(formatDataObject(tag, value));
1356
+ }
1357
+ }
1358
+ return segments.join("");
1359
+ }
1360
+ function mapMerchantChannelFromType(value) {
1361
+ return value === "DYNAMIC" ? "400" : "000";
1362
+ }
1363
+ function mapQrTypeFromChannel(channel) {
1364
+ const normalized = channel?.trim().toUpperCase();
1365
+ if (normalized === "400") {
1366
+ return "DYNAMIC";
1367
+ }
1368
+ return "STATIC";
1369
+ }
1370
+ function formatDataObject(id, value) {
1371
+ const length = value.length.toString().padStart(2, "0");
1372
+ return `${id}${length}${value}`;
1373
+ }
1374
+ function sanitizeAmount(value) {
1375
+ return typeof value === "number" ? value.toString() : value.trim();
1376
+ }
1377
+ function validateSubTag(tag) {
1378
+ if (!/^[0-9A-Za-z]{2}$/.test(tag)) {
1379
+ throw new Error(
1380
+ `Le sous-tag additional data "${tag}" doit contenir exactement 2 caract\xE8res alphanum\xE9riques.`
1381
+ );
1382
+ }
1383
+ }
1384
+ function validateAlias(alias) {
1385
+ const uuidV4Regex = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
1386
+ if (!uuidV4Regex.test(alias)) {
1387
+ throw new Error("L'alias doit \xEAtre un UUID v4 valide.");
1388
+ }
1389
+ }
1390
+ function validateReferenceLabel(reference) {
1391
+ if (reference.length > 25) {
1392
+ throw new Error("Le referenceLabel ne doit pas d\xE9passer 25 caract\xE8res.");
1393
+ }
1394
+ }
1395
+ function normalizeQrType(type) {
1396
+ const normalized = type.trim().toUpperCase();
1397
+ if (normalized === "STATIC" || normalized === "DYNAMIC") {
1398
+ return normalized;
1399
+ }
1400
+ throw new Error('Le param\xE8tre "qrType" doit \xEAtre "STATIC" ou "DYNAMIC".');
1401
+ }
1402
+ var UEMOA_COUNTRIES = /* @__PURE__ */ new Set(["BJ", "BF", "CI", "ML", "NE", "SN", "TG", "GW"]);
1403
+ function validateCountryCode(code) {
1404
+ if (!UEMOA_COUNTRIES.has(code.toUpperCase())) {
1405
+ throw new Error("Le countryCode doit \xEAtre l'un des codes ISO2 de l'UEMOA (BJ, BF, CI, ML, NE, SN, TG, GW).");
1406
+ }
1407
+ }
1408
+ function validateAmount(amount) {
1409
+ const normalized = typeof amount === "number" ? amount.toString() : amount.trim();
1410
+ if (!/^\d+$/.test(normalized)) {
1411
+ throw new Error("Le montant doit contenir uniquement des chiffres.");
1412
+ }
1413
+ if (normalized.length > 13) {
1414
+ throw new Error("Le montant ne doit pas d\xE9passer 13 chiffres.");
1415
+ }
1416
+ }
1417
+ function computeCrc16(input) {
1418
+ let crc = 65535;
1419
+ const polynomial = 4129;
1420
+ for (let i = 0; i < input.length; i += 1) {
1421
+ crc ^= (input.codePointAt(i) ?? 0) << 8;
1422
+ for (let j = 0; j < 8; j += 1) {
1423
+ const hasHighBit = (crc & 32768) === 0;
1424
+ crc = hasHighBit ? crc << 1 : crc << 1 ^ polynomial;
1425
+ crc &= 65535;
1426
+ }
1427
+ }
1428
+ return crc.toString(16).toUpperCase().padStart(4, "0");
1429
+ }
1430
+ function buildPayloadString(params, options) {
1431
+ return createQrPayload(params, options).payload;
1432
+ }
1433
+ async function generateQrCodeSvg(input, options = {}) {
1434
+ const { payload } = createQrPayload(input);
1435
+ const size = options.size ?? DEFAULT_SVG_SIZE;
1436
+ const margin = options.margin ?? DEFAULT_MARGIN;
1437
+ const module = await getQrCodeModule();
1438
+ const qr = module.create(payload, {
1439
+ errorCorrectionLevel: "M"
1440
+ });
1441
+ const dotColor = options.dotColor ?? DEFAULT_DOT_COLOR;
1442
+ const backgroundColor = options.backgroundColor ?? DEFAULT_BACKGROUND_COLOR;
1443
+ return buildDotPatternSvg(qr, {
1444
+ size,
1445
+ margin,
1446
+ dotColor,
1447
+ backgroundColor,
1448
+ logo: {
1449
+ dataUrl: options.logoDataUrl ?? DEFAULT_PISPI_LOGO_DATA_URL,
1450
+ sizeRatio: options.logoSizeRatio ?? DEFAULT_LOGO_SIZE_RATIO,
1451
+ paddingRatio: options.logoPaddingRatio ?? DEFAULT_LOGO_PADDING_RATIO,
1452
+ borderRadiusRatio: options.logoBorderRadiusRatio ?? DEFAULT_LOGO_BORDER_RADIUS_RATIO,
1453
+ backgroundColor: options.logoBackgroundColor ?? DEFAULT_BACKGROUND_COLOR
1454
+ }
1455
+ });
1456
+ }
1457
+ function clamp(value, min, max) {
1458
+ return Math.min(Math.max(value, min), max);
1459
+ }
1460
+ function formatSvgNumber(value) {
1461
+ const normalized = Number.parseFloat(value.toFixed(3));
1462
+ if (Number.isNaN(normalized)) {
1463
+ return "0";
1464
+ }
1465
+ return normalized.toString();
1466
+ }
1467
+ var QRCode = {
1468
+ // Original methods
1469
+ createQrPayload,
1470
+ buildPayloadString,
1471
+ computeCrc16,
1472
+ generateQrCodeSvg,
1473
+ isValidPispiQrPayload,
1474
+ // Simplified aliases
1475
+ payload: buildPayloadString,
1476
+ svg: generateQrCodeSvg,
1477
+ validate: isValidPispiQrPayload,
1478
+ raw: createQrPayload
1479
+ // For when you need the object wrapper
1480
+ };
1481
+ function isValidPispiQrPayload(value) {
1482
+ const basicErrors = validatePayloadBasics(value);
1483
+ if (basicErrors.length > 0) {
1484
+ return { valid: false, errors: basicErrors };
1485
+ }
1486
+ const { segments, errors: parseErrors } = parseEmvSegments(value);
1487
+ if (parseErrors.length > 0) {
1488
+ return { valid: false, errors: parseErrors };
1489
+ }
1490
+ const segmentValidation = validateSegmentContent(segments, value);
1491
+ if (segmentValidation.errors.length > 0) {
1492
+ return { valid: false, errors: segmentValidation.errors };
1493
+ }
1494
+ const data = buildValidationData(segments, segmentValidation);
1495
+ return {
1496
+ valid: true,
1497
+ errors: [],
1498
+ data
1499
+ };
1500
+ }
1501
+ function validatePayloadBasics(value) {
1502
+ if (!value) {
1503
+ return ["La payload doit \xEAtre une cha\xEEne non vide."];
1504
+ }
1505
+ if (value.length < 12) {
1506
+ return ["Payload trop courte pour contenir des segments EMV."];
1507
+ }
1508
+ return [];
1509
+ }
1510
+ function parseEmvSegments(value) {
1511
+ const segments = {};
1512
+ const errors = [];
1513
+ let cursor = 0;
1514
+ try {
1515
+ while (cursor < value.length) {
1516
+ const tag = value.slice(cursor, cursor + 2);
1517
+ const lengthStr = value.slice(cursor + 2, cursor + 4);
1518
+ const length = Number.parseInt(lengthStr, 10);
1519
+ if (Number.isNaN(length) || length < 0) {
1520
+ errors.push(`Longueur invalide pour le tag ${tag}.`);
1521
+ break;
1522
+ }
1523
+ const valueStart = cursor + 4;
1524
+ const valueEnd = valueStart + length;
1525
+ if (valueEnd > value.length) {
1526
+ errors.push(`Segment ${tag} tronqu\xE9.`);
1527
+ break;
1528
+ }
1529
+ segments[tag] = value.slice(valueStart, valueEnd);
1530
+ cursor = valueEnd;
1531
+ }
1532
+ } catch (error) {
1533
+ errors.push(`Erreur lors de l'analyse de la payload: ${error?.message ?? error}`);
1534
+ }
1535
+ return { segments, errors };
1536
+ }
1537
+ function validateSegmentContent(segments, rawValue) {
1538
+ const errors = [];
1539
+ const formatErrors = validateFormatIndicator(segments["00"]);
1540
+ const merchantInfoResult = extractMerchantInfo(segments["36"]);
1541
+ const countryCodeResult = validateCountryCodeSegment(segments["58"]);
1542
+ const additionalDataResult = extractAdditionalData(segments["62"]);
1543
+ const crcErrors = validateCrcSegment(segments["63"], rawValue);
1544
+ errors.push(
1545
+ ...formatErrors,
1546
+ ...merchantInfoResult.errors,
1547
+ ...countryCodeResult.errors,
1548
+ ...additionalDataResult.errors,
1549
+ ...crcErrors
1550
+ );
1551
+ return {
1552
+ errors,
1553
+ merchantInfo: merchantInfoResult.merchantInfo,
1554
+ referenceLabel: additionalDataResult.referenceLabel,
1555
+ merchantChannel: additionalDataResult.merchantChannel,
1556
+ countryCode: countryCodeResult.countryCode
1557
+ };
1558
+ }
1559
+ function validateFormatIndicator(formatIndicator) {
1560
+ if (!formatIndicator) {
1561
+ return ["Tag 00 (format indicator) manquant."];
1562
+ }
1563
+ if (formatIndicator !== "01") {
1564
+ return ["Tag 00 invalide (doit \xEAtre 01)."];
1565
+ }
1566
+ return [];
1567
+ }
1568
+ function extractMerchantInfo(segment) {
1569
+ if (!segment) {
1570
+ return {
1571
+ merchantInfo: null,
1572
+ errors: ["Tag 36 (Merchant Account Information) manquant."]
1573
+ };
1574
+ }
1575
+ try {
1576
+ const merchantInfo = parseSubFields(segment);
1577
+ const errors = [];
1578
+ if (!merchantInfo["01"]) {
1579
+ errors.push("Alias manquant dans les informations marchand (tag 36).");
1580
+ }
1581
+ return { merchantInfo, errors };
1582
+ } catch (error) {
1583
+ return {
1584
+ merchantInfo: null,
1585
+ errors: [`Erreur lors de l'analyse des informations marchand: ${error?.message ?? error}`]
1586
+ };
1587
+ }
1588
+ }
1589
+ function validateCountryCodeSegment(countryCode) {
1590
+ if (!countryCode) {
1591
+ return {
1592
+ errors: ["Tag 58 (Country Code) manquant."]
1593
+ };
1594
+ }
1595
+ return {
1596
+ countryCode,
1597
+ errors: []
1598
+ };
1599
+ }
1600
+ function extractAdditionalData(segment) {
1601
+ if (!segment) {
1602
+ return {
1603
+ errors: ["Tag 62 (Additional Data Field) manquant."]
1604
+ };
1605
+ }
1606
+ try {
1607
+ const additionalSegments = parseSubFields(segment);
1608
+ const referenceLabel = additionalSegments["05"];
1609
+ const merchantChannel = additionalSegments[DEFAULT_MERCHANT_CHANNEL_TAG];
1610
+ const errors = [];
1611
+ if (!merchantChannel) {
1612
+ errors.push("Tag 11 (Merchant Channel) manquant dans les donn\xE9es additionnelles.");
1613
+ }
1614
+ return {
1615
+ referenceLabel,
1616
+ merchantChannel,
1617
+ errors
1618
+ };
1619
+ } catch (error) {
1620
+ return {
1621
+ errors: [`Erreur lors de l'analyse des donn\xE9es additionnelles: ${error?.message ?? error}`]
1622
+ };
1623
+ }
1624
+ }
1625
+ function validateCrcSegment(crc, rawValue) {
1626
+ if (!crc) {
1627
+ return ["Tag 63 (CRC) manquant."];
1628
+ }
1629
+ const payloadWithoutCrc = rawValue.slice(0, -4);
1630
+ const computedCrc = computeCrc16(payloadWithoutCrc);
1631
+ if (crc !== computedCrc) {
1632
+ return ["CRC invalide."];
1633
+ }
1634
+ return [];
1635
+ }
1636
+ function buildValidationData(segments, context) {
1637
+ const amountValue = segments["54"];
1638
+ const data = {
1639
+ alias: context.merchantInfo?.["01"] ?? "",
1640
+ countryCode: context.countryCode ?? "",
1641
+ qrType: mapQrTypeFromChannel(context.merchantChannel),
1642
+ referenceLabel: context.referenceLabel ?? ""
1643
+ // Chaîne vide si Tag 05 est absent (optionnel)
1644
+ };
1645
+ if (amountValue !== void 0) {
1646
+ data.amount = amountValue;
1647
+ }
1648
+ return data;
1649
+ }
1650
+ function parseSubFields(data) {
1651
+ const segments = {};
1652
+ let cursor = 0;
1653
+ while (cursor < data.length) {
1654
+ const tag = data.slice(cursor, cursor + 2);
1655
+ const lengthStr = data.slice(cursor + 2, cursor + 4);
1656
+ const length = Number.parseInt(lengthStr, 10);
1657
+ if (Number.isNaN(length) || length < 0) {
1658
+ throw new Error(`Longueur invalide pour le sous-tag ${tag}`);
1659
+ }
1660
+ const valueStart = cursor + 4;
1661
+ const valueEnd = valueStart + length;
1662
+ if (valueEnd > data.length) {
1663
+ throw new Error(`Sous-segment ${tag} tronqu\xE9`);
1664
+ }
1665
+ const segmentValue = data.slice(valueStart, valueEnd);
1666
+ segments[tag] = segmentValue;
1667
+ cursor = valueEnd;
1668
+ }
1669
+ return segments;
1670
+ }
1671
+ function buildDotPatternSvg(qr, options) {
1672
+ const modules = qr.modules;
1673
+ const moduleCount = typeof modules?.size === "number" ? modules.size : modules.length;
1674
+ if (typeof moduleCount !== "number" || Number.isNaN(moduleCount)) {
1675
+ throw new TypeError("Format du QR Code inattendu: impossible de d\xE9terminer la taille de la matrice.");
1676
+ }
1677
+ const svgSize = options.size;
1678
+ const margin = options.margin;
1679
+ const drawableSize = svgSize - margin * 2;
1680
+ const cellSize = drawableSize / moduleCount;
1681
+ const dotRadius = cellSize * DOT_RADIUS_RATIO;
1682
+ const finderRadius = cellSize * FINDER_CORNER_RADIUS;
1683
+ const paths = [];
1684
+ const backgroundRect = `<rect fill="${options.backgroundColor}" width="${svgSize}" height="${svgSize}" rx="${formatSvgNumber(
1685
+ finderRadius
1686
+ )}" />`;
1687
+ const finderSize = 7;
1688
+ const finderOrigins = [
1689
+ [0, 0],
1690
+ [moduleCount - finderSize, 0],
1691
+ [0, moduleCount - finderSize]
1692
+ ];
1693
+ for (const [fc, fr] of finderOrigins) {
1694
+ paths.push(
1695
+ ...generateFinderPatternRects(
1696
+ margin + fc * cellSize,
1697
+ margin + fr * cellSize,
1698
+ cellSize,
1699
+ options.dotColor,
1700
+ options.backgroundColor
1701
+ )
1702
+ );
1703
+ }
1704
+ for (let row = 0; row < moduleCount; row += 1) {
1705
+ for (let col = 0; col < moduleCount; col += 1) {
1706
+ if (!isDarkModule(modules, moduleCount, row, col)) {
1707
+ continue;
1708
+ }
1709
+ if (isFinderPattern(moduleCount, row, col)) {
1710
+ continue;
1711
+ }
1712
+ const x = margin + col * cellSize + cellSize / 2;
1713
+ const y = margin + row * cellSize + cellSize / 2;
1714
+ paths.push(
1715
+ `<circle cx="${formatSvgNumber(x)}" cy="${formatSvgNumber(y)}" r="${formatSvgNumber(
1716
+ dotRadius
1717
+ )}" fill="${options.dotColor}" />`
1718
+ );
1719
+ }
1720
+ }
1721
+ const logoSvg = generateLogoOverlay(
1722
+ svgSize,
1723
+ margin,
1724
+ moduleCount,
1725
+ cellSize,
1726
+ options.logo
1727
+ );
1728
+ return [
1729
+ `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 ${svgSize} ${svgSize}" shape-rendering="geometricPrecision">`,
1730
+ backgroundRect,
1731
+ ...paths,
1732
+ logoSvg,
1733
+ "</svg>"
1734
+ ].join("");
1735
+ }
1736
+ function isFinderPattern(moduleCount, row, col) {
1737
+ const patternSize = 7;
1738
+ const inTop = row < patternSize;
1739
+ const inBottom = row >= moduleCount - patternSize;
1740
+ const inLeft = col < patternSize;
1741
+ const inRight = col >= moduleCount - patternSize;
1742
+ return inTop && inLeft || inTop && inRight || inBottom && inLeft;
1743
+ }
1744
+ function generateFinderPatternRects(originX, originY, cellSize, dotColor, backgroundColor) {
1745
+ const fmt = formatSvgNumber;
1746
+ const out7 = cellSize * 7;
1747
+ const out5 = cellSize * 5;
1748
+ const out3 = cellSize * 3;
1749
+ const off1 = cellSize;
1750
+ const off2 = cellSize * 2;
1751
+ return [
1752
+ `<rect x="${fmt(originX)}" y="${fmt(originY)}" width="${fmt(out7)}" height="${fmt(out7)}" fill="${dotColor}" />`,
1753
+ `<rect x="${fmt(originX + off1)}" y="${fmt(originY + off1)}" width="${fmt(out5)}" height="${fmt(out5)}" fill="${backgroundColor}" />`,
1754
+ `<rect x="${fmt(originX + off2)}" y="${fmt(originY + off2)}" width="${fmt(out3)}" height="${fmt(out3)}" fill="${dotColor}" />`
1755
+ ];
1756
+ }
1757
+ function generateLogoOverlay(svgSize, margin, moduleCount, cellSize, logo) {
1758
+ if (!logo.dataUrl) {
1759
+ return "";
1760
+ }
1761
+ const qrDrawableSize = moduleCount * cellSize;
1762
+ const logoSize = qrDrawableSize * clamp(logo.sizeRatio, 0.05, 0.5);
1763
+ const logoPadding = logoSize * clamp(logo.paddingRatio, 0, 0.25);
1764
+ const backgroundSize = logoSize + logoPadding * 2;
1765
+ const logoBorderRadius = clamp(logo.borderRadiusRatio, 0, 0.5) * backgroundSize;
1766
+ const originX = margin + (qrDrawableSize - backgroundSize) / 2;
1767
+ const originY = margin + (qrDrawableSize - backgroundSize) / 2;
1768
+ return [
1769
+ `<g class="pispi-logo" transform="translate(${formatSvgNumber(originX)}, ${formatSvgNumber(originY)})" pointer-events="none">`,
1770
+ `<rect width="${formatSvgNumber(backgroundSize)}" height="${formatSvgNumber(backgroundSize)}" rx="${formatSvgNumber(
1771
+ logoBorderRadius
1772
+ )}" fill="${logo.backgroundColor}" opacity="0.95"/>`,
1773
+ `<image x="${formatSvgNumber(logoPadding)}" y="${formatSvgNumber(logoPadding)}" width="${formatSvgNumber(
1774
+ logoSize
1775
+ )}" height="${formatSvgNumber(logoSize)}" href="${logo.dataUrl}" xlink:href="${logo.dataUrl}" preserveAspectRatio="xMidYMid meet"/>`,
1776
+ "</g>"
1777
+ ].join("");
1778
+ }
1779
+ function isDarkModule(modules, moduleCount, row, col) {
1780
+ if (modules?.data && Array.isArray(modules.data)) {
1781
+ const index = row * moduleCount + col;
1782
+ return Boolean(modules.data[index]);
1783
+ }
1784
+ if (typeof modules?.get === "function") {
1785
+ return Boolean(modules.get(row, col));
1786
+ }
1787
+ if (Array.isArray(modules[row])) {
1788
+ return Boolean(modules[row][col]);
1789
+ }
1790
+ return false;
1791
+ }
1792
+
1793
+ // src/sdk.ts
1794
+ var OpenAPI2;
1795
+ var PiSpiSDK = class {
1796
+ /**
1797
+ * Initialize the PI-SPI SDK
1798
+ *
1799
+ * @param config - SDK configuration
1800
+ *
1801
+ * @example
1802
+ * ```typescript
1803
+ * const sdk = new PiSpiSDK({
1804
+ * baseUrl: 'https://sandbox.api.pi-bceao.com/piz/v1',
1805
+ * accessToken: 'your-oauth2-token',
1806
+ * });
1807
+ * ```
1808
+ */
1809
+ constructor(config) {
1810
+ /**
1811
+ * QR Code utilities
1812
+ * Generate and validate BCEAO compatible QR codes
1813
+ */
1814
+ this.qr = QRCode;
1815
+ this._config = {
1816
+ BASE: config.baseUrl || "https://sandbox.api.pi-bceao.com/piz/v1",
1817
+ TOKEN: config.accessToken,
1818
+ dispatcher: config.dispatcher,
1819
+ HEADERS: {
1820
+ ...config.headers
1821
+ }
1822
+ };
1823
+ try {
1824
+ OpenAPI2 = this._config;
1825
+ } catch {
1826
+ OpenAPI2 = this._config;
1827
+ }
1828
+ this.comptes = new ComptesService2(this._config);
1829
+ this.alias = new AliasService2(this._config);
1830
+ this.webhooks = new WebhooksService(this._config);
1831
+ this.demandesPaiement = new DemandesPaiementService(this._config);
1832
+ this.demandesPaiementEnMasse = new DemandesPaiementEnMasseService(this._config);
1833
+ this.paiements = new PaiementsService(this._config);
1834
+ this.paiementsEnMasse = new PaiementsEnMasseService(this._config);
1835
+ this.retoursFonds = new RetoursFondsService(this._config);
1836
+ this.demandesAnnulation = new DemandesAnnulationService(this._config);
1837
+ }
1838
+ /**
1839
+ * Update the access token
1840
+ * Useful when tokens are refreshed
1841
+ */
1842
+ setAccessToken(token) {
1843
+ if (this._config) {
1844
+ this._config.TOKEN = token;
1845
+ }
1846
+ if (OpenAPI2) {
1847
+ OpenAPI2.TOKEN = token;
1848
+ OpenAPI2.HEADERS = {
1849
+ ...OpenAPI2.HEADERS,
1850
+ Authorization: `Bearer ${token}`
1851
+ };
1852
+ }
1853
+ }
1854
+ /**
1855
+ * Get the current base URL
1856
+ */
1857
+ getBaseUrl() {
1858
+ return this._config.BASE;
1859
+ }
1860
+ };
1861
+
1862
+ // src/customer-qr.ts
1863
+ var ALIAS_TYPES = ["SHID", "MBNO", "MCOD"];
1864
+ function buildLomiCustomerQr(input) {
1865
+ const alias = input.alias.trim();
1866
+ if (!alias) {
1867
+ throw new Error("alias is required");
1868
+ }
1869
+ const aliasType = input.aliasType ?? "SHID";
1870
+ if (!ALIAS_TYPES.includes(aliasType)) {
1871
+ throw new Error(`Invalid aliasType: ${aliasType}`);
1872
+ }
1873
+ return {
1874
+ t: "lomi.cust",
1875
+ v: 1,
1876
+ alias,
1877
+ aliasType
1878
+ };
1879
+ }
1880
+ function serializeLomiCustomerQr(qr) {
1881
+ return JSON.stringify(qr);
1882
+ }
1883
+ function parseLomiCustomerQr(raw) {
1884
+ const trimmed = raw.trim();
1885
+ if (!trimmed || trimmed.startsWith("000201")) {
1886
+ return null;
1887
+ }
1888
+ let parsed;
1889
+ try {
1890
+ parsed = JSON.parse(trimmed);
1891
+ } catch {
1892
+ return null;
1893
+ }
1894
+ if (typeof parsed !== "object" || parsed === null) {
1895
+ return null;
1896
+ }
1897
+ const record = parsed;
1898
+ if (record.t !== "lomi.cust" || record.v !== 1) {
1899
+ return null;
1900
+ }
1901
+ const alias = record.alias;
1902
+ if (typeof alias !== "string" || alias.trim().length === 0) {
1903
+ return null;
1904
+ }
1905
+ const aliasType = record.aliasType;
1906
+ if (typeof aliasType !== "string" || !ALIAS_TYPES.includes(aliasType)) {
1907
+ return null;
1908
+ }
1909
+ return {
1910
+ t: "lomi.cust",
1911
+ v: 1,
1912
+ alias: alias.trim(),
1913
+ aliasType
1914
+ };
1915
+ }
1916
+
1917
+ // src/query-builder.ts
1918
+ var QueryBuilder = class {
1919
+ constructor() {
1920
+ this.params = {};
1921
+ this.filters = /* @__PURE__ */ new Map();
1922
+ this.sortOrder = "asc";
1923
+ }
1924
+ /**
1925
+ * Add a filter condition
1926
+ * @param field - Field name to filter on
1927
+ * @param operator - Filter operator (default: 'eq')
1928
+ * @param value - Filter value
1929
+ */
1930
+ filter(field, operatorOrValue, value) {
1931
+ let operator;
1932
+ let filterValue;
1933
+ if (value === void 0) {
1934
+ if (typeof operatorOrValue === "string" && this.isOperator(operatorOrValue)) {
1935
+ throw new Error("Filter operator requires a value");
1936
+ }
1937
+ operator = "eq";
1938
+ filterValue = operatorOrValue;
1939
+ } else {
1940
+ operator = operatorOrValue;
1941
+ filterValue = value;
1942
+ }
1943
+ this.filters.set(field, { operator, value: filterValue });
1944
+ return this;
1945
+ }
1946
+ /**
1947
+ * Add an equality filter (shorthand)
1948
+ */
1949
+ eq(field, value) {
1950
+ return this.filter(field, "eq", value);
1951
+ }
1952
+ /**
1953
+ * Add a "not equal" filter (shorthand)
1954
+ */
1955
+ ne(field, value) {
1956
+ return this.filter(field, "ne", value);
1957
+ }
1958
+ /**
1959
+ * Add a "greater than" filter (shorthand)
1960
+ */
1961
+ gt(field, value) {
1962
+ return this.filter(field, "gt", value);
1963
+ }
1964
+ /**
1965
+ * Add a "greater than or equal" filter (shorthand)
1966
+ */
1967
+ gte(field, value) {
1968
+ return this.filter(field, "gte", value);
1969
+ }
1970
+ /**
1971
+ * Add a "less than" filter (shorthand)
1972
+ */
1973
+ lt(field, value) {
1974
+ return this.filter(field, "lt", value);
1975
+ }
1976
+ /**
1977
+ * Add a "less than or equal" filter (shorthand)
1978
+ */
1979
+ lte(field, value) {
1980
+ return this.filter(field, "lte", value);
1981
+ }
1982
+ /**
1983
+ * Add an "in" filter (shorthand)
1984
+ */
1985
+ in(field, values) {
1986
+ return this.filter(field, "in", values);
1987
+ }
1988
+ /**
1989
+ * Add a "contains" filter (shorthand)
1990
+ */
1991
+ contains(field, value) {
1992
+ return this.filter(field, "contains", value);
1993
+ }
1994
+ /**
1995
+ * Set sort field and order
1996
+ * @param field - Field to sort by
1997
+ * @param order - Sort order ('asc' or 'desc', default: 'asc')
1998
+ */
1999
+ sort(field, order = "asc") {
2000
+ this.sortField = field;
2001
+ this.sortOrder = order;
2002
+ return this;
2003
+ }
2004
+ /**
2005
+ * Sort in descending order (shorthand)
2006
+ */
2007
+ sortDesc(field) {
2008
+ return this.sort(field, "desc");
2009
+ }
2010
+ /**
2011
+ * Set page number
2012
+ */
2013
+ page(page) {
2014
+ this.params.page = typeof page === "string" ? page : page.toString();
2015
+ return this;
2016
+ }
2017
+ /**
2018
+ * Set page size
2019
+ */
2020
+ size(size) {
2021
+ if (size < 1) {
2022
+ throw new Error("Page size must be at least 1");
2023
+ }
2024
+ if (size > 100) {
2025
+ throw new Error("Page size cannot exceed 100");
2026
+ }
2027
+ this.params.size = size;
2028
+ return this;
2029
+ }
2030
+ /**
2031
+ * Add a custom parameter
2032
+ */
2033
+ param(key, value) {
2034
+ this.params[key] = value;
2035
+ return this;
2036
+ }
2037
+ /**
2038
+ * Build the query parameters object
2039
+ */
2040
+ build() {
2041
+ const result = { ...this.params };
2042
+ for (const [field, { operator, value }] of this.filters.entries()) {
2043
+ if (operator === "eq") {
2044
+ result[field] = String(value);
2045
+ } else if (operator === "exists") {
2046
+ result[`${field}[exists]`] = String(value);
2047
+ } else {
2048
+ result[`${field}[${operator}]`] = Array.isArray(value) ? value.join(",") : String(value);
2049
+ }
2050
+ }
2051
+ if (this.sortField) {
2052
+ result.sort = this.sortOrder === "desc" ? `-${this.sortField}` : this.sortField;
2053
+ }
2054
+ return result;
2055
+ }
2056
+ /**
2057
+ * Build query string
2058
+ */
2059
+ buildQueryString() {
2060
+ const params = this.build();
2061
+ const pairs = Object.entries(params).filter(([_, value]) => value !== void 0).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);
2062
+ return pairs.length > 0 ? `?${pairs.join("&")}` : "";
2063
+ }
2064
+ /**
2065
+ * Reset the builder
2066
+ */
2067
+ reset() {
2068
+ this.params = {};
2069
+ this.filters.clear();
2070
+ this.sortField = void 0;
2071
+ this.sortOrder = "asc";
2072
+ return this;
2073
+ }
2074
+ isOperator(value) {
2075
+ return [
2076
+ "eq",
2077
+ "ne",
2078
+ "gt",
2079
+ "gte",
2080
+ "lt",
2081
+ "lte",
2082
+ "in",
2083
+ "contains",
2084
+ "notContains",
2085
+ "beginsWith",
2086
+ "endsWith",
2087
+ "exists"
2088
+ ].includes(value);
2089
+ }
2090
+ };
2091
+
2092
+ // src/types/alias.ts
2093
+ var AliasType = {
2094
+ /**
2095
+ * SHID - System-generated unique payment address (UUID format, 36 characters)
2096
+ * Available for all client types: P, C, B, G
2097
+ */
2098
+ SHID: "SHID",
2099
+ /**
2100
+ * MCOD - Merchant code for USSD payment support
2101
+ * Available for business clients only: C, B, G
2102
+ */
2103
+ MCOD: "MCOD",
2104
+ /**
2105
+ * MBNO - Mobile phone number alias
2106
+ * Available for individual clients only: P
2107
+ */
2108
+ MBNO: "MBNO"
2109
+ };
2110
+ var ALIAS_TYPES2 = [AliasType.SHID, AliasType.MCOD, AliasType.MBNO];
2111
+ function isValidAliasType(value) {
2112
+ return ALIAS_TYPES2.includes(value);
2113
+ }
2114
+ function getAvailableAliasTypes(clientType) {
2115
+ switch (clientType) {
2116
+ case "P":
2117
+ return [AliasType.MBNO, AliasType.SHID];
2118
+ case "C":
2119
+ case "B":
2120
+ case "G":
2121
+ return [AliasType.SHID, AliasType.MCOD];
2122
+ default:
2123
+ return [];
2124
+ }
2125
+ }
2126
+
2127
+ // src/utils/index.ts
2128
+ function formatAmount(centimes) {
2129
+ const xof = centimes / 100;
2130
+ return new Intl.NumberFormat("fr-FR", {
2131
+ style: "currency",
2132
+ currency: "XOF",
2133
+ minimumFractionDigits: 0,
2134
+ maximumFractionDigits: 0
2135
+ }).format(xof);
2136
+ }
2137
+ function xofToCentimes(xof) {
2138
+ return Math.round(xof * 100);
2139
+ }
2140
+ function centimesToXof(centimes) {
2141
+ return centimes / 100;
2142
+ }
2143
+ function isValidAccountNumber(accountNumber) {
2144
+ return /^[A-Z]{2,3}\d{19,22}$/.test(accountNumber);
2145
+ }
2146
+ function isValidShidAlias(alias) {
2147
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
2148
+ return uuidRegex.test(alias);
2149
+ }
2150
+ function isValidPhoneNumber(phoneNumber) {
2151
+ const phoneRegex = /^\+?[1-9]\d{8,12}$/;
2152
+ return phoneRegex.test(phoneNumber.replace(/[\s-]/g, ""));
2153
+ }
2154
+ function getCountryFromAccount(accountNumber) {
2155
+ const countryMap = {
2156
+ CI: "C\xF4te d'Ivoire",
2157
+ SN: "Senegal",
2158
+ BJ: "Benin",
2159
+ BF: "Burkina Faso",
2160
+ ML: "Mali",
2161
+ NE: "Niger",
2162
+ TG: "Togo",
2163
+ GW: "Guinea-Bissau"
2164
+ };
2165
+ const countryCode = accountNumber.substring(0, 2);
2166
+ return countryMap[countryCode] || null;
2167
+ }
2168
+ function sleep(ms) {
2169
+ return new Promise((resolve) => setTimeout(resolve, ms));
2170
+ }
2171
+ async function retryWithBackoff(fn, maxRetries = 3, initialDelay = 1e3) {
2172
+ let lastError;
2173
+ for (let i = 0; i < maxRetries; i++) {
2174
+ try {
2175
+ return await fn();
2176
+ } catch (error) {
2177
+ lastError = error instanceof Error ? error : new Error(String(error));
2178
+ if (i < maxRetries - 1) {
2179
+ const delay = initialDelay * Math.pow(2, i);
2180
+ await sleep(delay);
2181
+ }
2182
+ }
2183
+ }
2184
+ throw lastError ?? new Error("Retry failed with unknown error");
2185
+ }
2186
+
2187
+ // src/utils/constants.ts
2188
+ var PI_SPI_ENDPOINTS = {
2189
+ /** Production API endpoint */
2190
+ PRODUCTION: "https://api.pi-bceao.com/piz/v1",
2191
+ /** Sandbox API endpoint */
2192
+ SANDBOX: "https://sandbox.api.pi-bceao.com/piz/v1",
2193
+ /** Default endpoint (sandbox) */
2194
+ DEFAULT: "https://sandbox.api.pi-bceao.com/piz/v1"
2195
+ };
2196
+ var PAYMENT_STATUS = {
2197
+ /** Payment initiated (awaiting confirmation after alias lookup) */
2198
+ INITIE: "INITIE",
2199
+ /** Payment sent (validations passed, PSP has sent the request) */
2200
+ ENVOYE: "ENVOYE",
2201
+ /** Payment is confirmed/irreversible */
2202
+ IRREVOCABLE: "IRREVOCABLE",
2203
+ /** Payment has been rejected */
2204
+ REJETE: "REJETE"
2205
+ };
2206
+ var ACCOUNT_STATUS = {
2207
+ /** Account is open */
2208
+ OPEN: "OUVERT",
2209
+ /** Account is blocked */
2210
+ BLOCKED: "BLOQUE",
2211
+ /** Account is closed */
2212
+ CLOSED: "CLOTURE"
2213
+ };
2214
+ var ACCOUNT_TYPE = {
2215
+ /** Current account */
2216
+ CURRENT: "CACC",
2217
+ /** Savings account */
2218
+ SAVINGS: "SVGS"
2219
+ };
2220
+ var CLIENT_TYPE = {
2221
+ /** Individual person */
2222
+ INDIVIDUAL: "P",
2223
+ /** Merchant */
2224
+ MERCHANT: "C",
2225
+ /** Business */
2226
+ BUSINESS: "B",
2227
+ /** Government */
2228
+ GOVERNMENT: "G"
2229
+ };
2230
+ var UEMOA_COUNTRIES2 = {
2231
+ BENIN: "BJ",
2232
+ BURKINA_FASO: "BF",
2233
+ IVORY_COAST: "CI",
2234
+ GUINEA_BISSAU: "GW",
2235
+ MALI: "ML",
2236
+ NIGER: "NE",
2237
+ SENEGAL: "SN",
2238
+ TOGO: "TG"
2239
+ };
2240
+ var CURRENCY = {
2241
+ /** West African CFA Franc */
2242
+ XOF: "XOF",
2243
+ /** Amounts are specified in centimes (1 XOF = 100 centimes) */
2244
+ CENTIMES_PER_XOF: 100
2245
+ };
2246
+ var DEFAULT_LIMITS = {
2247
+ /** Maximum page size for paginated requests */
2248
+ MAX_PAGE_SIZE: 100,
2249
+ /** Default page size */
2250
+ DEFAULT_PAGE_SIZE: 20,
2251
+ /** Default aliases per account */
2252
+ DEFAULT_ALIASES_PER_ACCOUNT: 20
2253
+ };
2254
+ var WEBHOOK_EVENTS = {
2255
+ /** Payment received */
2256
+ PAIEMENT_RECU: "PAIEMENT_RECU",
2257
+ /** Payment sent */
2258
+ PAIEMENT_ENVOYE: "PAIEMENT_ENVOYE",
2259
+ /** Payment rejected */
2260
+ PAIEMENT_REJETE: "PAIEMENT_REJETE",
2261
+ /** Payment request (RTP) received */
2262
+ RTP_RECU: "RTP_RECU",
2263
+ /** Payment request (RTP) rejected */
2264
+ RTP_REJETE: "RTP_REJETE",
2265
+ /** Cancellation requested */
2266
+ ANNULATION_DEMANDE: "ANNULATION_DEMANDE",
2267
+ /** Cancellation rejected */
2268
+ ANNULATION_REJETE: "ANNULATION_REJETE",
2269
+ /** Fund return sent */
2270
+ RETOUR_ENVOYE: "RETOUR_ENVOYE",
2271
+ /** Fund return rejected */
2272
+ RETOUR_REJETE: "RETOUR_REJETE",
2273
+ /** Fund return received */
2274
+ RETOUR_RECU: "RETOUR_RECU"
2275
+ };
2276
+ export {
2277
+ ACCOUNT_STATUS,
2278
+ ACCOUNT_TYPE,
2279
+ ALIAS_TYPES2 as ALIAS_TYPES,
2280
+ AliasService,
2281
+ AliasType,
2282
+ AnnulationStatut,
2283
+ ApiError,
2284
+ CLIENT_TYPE,
2285
+ CURRENCY,
2286
+ CancelError,
2287
+ CancelablePromise,
2288
+ CompteOperation,
2289
+ CompteSolde,
2290
+ CompteTransfertIntraReponse,
2291
+ ComptesService,
2292
+ DEFAULT_LIMITS,
2293
+ DEFAULT_PISPI_LOGO_DATA_URL,
2294
+ DemandeAnnulationService,
2295
+ DemandePaiementConfirmationAnnulationRaison,
2296
+ DemandePaiementConfirmationReponse,
2297
+ DemandePaiementConsultationReponse,
2298
+ DemandePaiementEnMasseStatutReponse,
2299
+ DemandePaiementListeItem,
2300
+ DemandePaiementReponseRequest,
2301
+ DemandePaiementRequest,
2302
+ DemandePaiementRequestCategorie,
2303
+ DemandePaiementStatut,
2304
+ DemandePaiementStatutRaison,
2305
+ DemandesDePaiementEnMasseService,
2306
+ DemandesDePaiementService,
2307
+ NotificationService,
2308
+ OpenAPI,
2309
+ PAYMENT_STATUS,
2310
+ PISPI_AMBER_LOGO_DATA_URL,
2311
+ PISPI_QRCODE_LOGO_DATA_URL,
2312
+ PI_SPI_ENDPOINTS,
2313
+ Paiement,
2314
+ PaiementAnnulationMotif,
2315
+ PaiementAnnulationStatutRaison,
2316
+ PaiementEnMasseReponseStatut,
2317
+ PaiementEnMasseService,
2318
+ PaiementImmediatConfirmationReponse,
2319
+ PaiementImmediatReponse,
2320
+ PaiementImmediatService,
2321
+ PaiementStatut,
2322
+ PaiementStatutRaison,
2323
+ PiSpiAuthError,
2324
+ PiSpiError,
2325
+ PiSpiNotFoundError,
2326
+ PiSpiRateLimitError,
2327
+ PiSpiSDK,
2328
+ PiSpiValidationError,
2329
+ QRCode,
2330
+ QueryBuilder,
2331
+ RefDocType,
2332
+ RetourStatut,
2333
+ RetourStatutRaison,
2334
+ RetoursdeFondsService,
2335
+ UEMOA_COUNTRIES2 as UEMOA_COUNTRIES,
2336
+ WEBHOOK_EVENTS,
2337
+ WebhookEvent,
2338
+ WebhooksEvents,
2339
+ buildLomiCustomerQr,
2340
+ buildPayloadString,
2341
+ centimesToXof,
2342
+ computeCrc16,
2343
+ createQrPayload,
2344
+ formatAmount,
2345
+ generateQrCodeSvg,
2346
+ getAvailableAliasTypes,
2347
+ getCountryFromAccount,
2348
+ handleApiError,
2349
+ isValidAccountNumber,
2350
+ isValidAliasType,
2351
+ isValidPhoneNumber,
2352
+ isValidPispiQrPayload,
2353
+ isValidShidAlias,
2354
+ parseLomiCustomerQr,
2355
+ retryWithBackoff,
2356
+ serializeLomiCustomerQr,
2357
+ sleep,
2358
+ xofToCentimes
2359
+ };