@alviere/core 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/LICENSE +201 -0
  2. package/dist/entities/constants/environment.d.ts +29 -0
  3. package/dist/entities/constants/environment.d.ts.map +1 -0
  4. package/dist/entities/constants/error-codes.d.ts +51 -0
  5. package/dist/entities/constants/error-codes.d.ts.map +1 -0
  6. package/dist/entities/errors/alcore-api.error.d.ts +19 -0
  7. package/dist/entities/errors/alcore-api.error.d.ts.map +1 -0
  8. package/dist/entities/interfaces/cryptor.interface.d.ts +10 -0
  9. package/dist/entities/interfaces/cryptor.interface.d.ts.map +1 -0
  10. package/dist/entities/interfaces/gateways/accounts.interface.d.ts +48 -0
  11. package/dist/entities/interfaces/gateways/accounts.interface.d.ts.map +1 -0
  12. package/dist/entities/interfaces/gateways/auth.interface.d.ts +10 -0
  13. package/dist/entities/interfaces/gateways/auth.interface.d.ts.map +1 -0
  14. package/dist/entities/interfaces/gateways/card-issuance.interface.d.ts +6 -0
  15. package/dist/entities/interfaces/gateways/card-issuance.interface.d.ts.map +1 -0
  16. package/dist/entities/interfaces/gateways/payment-instruments.interface.d.ts +14 -0
  17. package/dist/entities/interfaces/gateways/payment-instruments.interface.d.ts.map +1 -0
  18. package/dist/entities/interfaces/gateways/payments.interface.d.ts +11 -0
  19. package/dist/entities/interfaces/gateways/payments.interface.d.ts.map +1 -0
  20. package/dist/entities/interfaces/gateways/transactions.interface.d.ts +32 -0
  21. package/dist/entities/interfaces/gateways/transactions.interface.d.ts.map +1 -0
  22. package/dist/entities/interfaces/gateways/wallets.interface.d.ts +11 -0
  23. package/dist/entities/interfaces/gateways/wallets.interface.d.ts.map +1 -0
  24. package/dist/entities/interfaces/logger.interface.d.ts +13 -0
  25. package/dist/entities/interfaces/logger.interface.d.ts.map +1 -0
  26. package/dist/entities/interfaces/validator.interface.d.ts +25 -0
  27. package/dist/entities/interfaces/validator.interface.d.ts.map +1 -0
  28. package/dist/entities/requests/_alcore.d.ts +9 -0
  29. package/dist/entities/requests/_alcore.d.ts.map +1 -0
  30. package/dist/entities/requests/accounts/accounts.d.ts +110 -0
  31. package/dist/entities/requests/accounts/accounts.d.ts.map +1 -0
  32. package/dist/entities/requests/accounts/addresses.d.ts +3 -0
  33. package/dist/entities/requests/accounts/addresses.d.ts.map +1 -0
  34. package/dist/entities/requests/accounts/dossiers.d.ts +36 -0
  35. package/dist/entities/requests/accounts/dossiers.d.ts.map +1 -0
  36. package/dist/entities/requests/auth/auth.d.ts +41 -0
  37. package/dist/entities/requests/auth/auth.d.ts.map +1 -0
  38. package/dist/entities/requests/card-issuance/card-issuance.d.ts +14 -0
  39. package/dist/entities/requests/card-issuance/card-issuance.d.ts.map +1 -0
  40. package/dist/entities/requests/payments/bank-accounts.d.ts +47 -0
  41. package/dist/entities/requests/payments/bank-accounts.d.ts.map +1 -0
  42. package/dist/entities/requests/payments/index.d.ts +4 -0
  43. package/dist/entities/requests/payments/index.d.ts.map +1 -0
  44. package/dist/entities/requests/payments/payment-instruments.d.ts +68 -0
  45. package/dist/entities/requests/payments/payment-instruments.d.ts.map +1 -0
  46. package/dist/entities/requests/payments/payments.d.ts +23 -0
  47. package/dist/entities/requests/payments/payments.d.ts.map +1 -0
  48. package/dist/entities/requests/transactions/transactions.d.ts +43 -0
  49. package/dist/entities/requests/transactions/transactions.d.ts.map +1 -0
  50. package/dist/entities/requests/utility.d.ts +61 -0
  51. package/dist/entities/requests/utility.d.ts.map +1 -0
  52. package/dist/entities/requests/wallets/wallets.d.ts +105 -0
  53. package/dist/entities/requests/wallets/wallets.d.ts.map +1 -0
  54. package/dist/entities/responses/accounts/accounts.d.ts +40 -0
  55. package/dist/entities/responses/accounts/accounts.d.ts.map +1 -0
  56. package/dist/entities/responses/accounts/addresses.d.ts +9 -0
  57. package/dist/entities/responses/accounts/addresses.d.ts.map +1 -0
  58. package/dist/entities/responses/accounts/dossiers.d.ts +26 -0
  59. package/dist/entities/responses/accounts/dossiers.d.ts.map +1 -0
  60. package/dist/entities/responses/alcore.d.ts +8 -0
  61. package/dist/entities/responses/alcore.d.ts.map +1 -0
  62. package/dist/entities/responses/auth/auth.d.ts +26 -0
  63. package/dist/entities/responses/auth/auth.d.ts.map +1 -0
  64. package/dist/entities/responses/card-issuance/set-pin.d.ts +6 -0
  65. package/dist/entities/responses/card-issuance/set-pin.d.ts.map +1 -0
  66. package/dist/entities/responses/payments/add_card.d.ts +27 -0
  67. package/dist/entities/responses/payments/add_card.d.ts.map +1 -0
  68. package/dist/entities/responses/payments/bank_accounts.d.ts +61 -0
  69. package/dist/entities/responses/payments/bank_accounts.d.ts.map +1 -0
  70. package/dist/entities/responses/payments/index.d.ts +4 -0
  71. package/dist/entities/responses/payments/index.d.ts.map +1 -0
  72. package/dist/entities/responses/payments/payment-instruments.d.ts +73 -0
  73. package/dist/entities/responses/payments/payment-instruments.d.ts.map +1 -0
  74. package/dist/entities/responses/transactions/transactions.d.ts +93 -0
  75. package/dist/entities/responses/transactions/transactions.d.ts.map +1 -0
  76. package/dist/entities/responses/wallets/wallets.d.ts +78 -0
  77. package/dist/entities/responses/wallets/wallets.d.ts.map +1 -0
  78. package/dist/entities/results/card-issuance/set-pin.d.ts +4 -0
  79. package/dist/entities/results/card-issuance/set-pin.d.ts.map +1 -0
  80. package/dist/entities/results/payments/add_bank_account.d.ts +47 -0
  81. package/dist/entities/results/payments/add_bank_account.d.ts.map +1 -0
  82. package/dist/entities/results/payments/add_card.d.ts +29 -0
  83. package/dist/entities/results/payments/add_card.d.ts.map +1 -0
  84. package/dist/index.d.ts +135 -0
  85. package/dist/index.d.ts.map +1 -0
  86. package/dist/index.js +2 -0
  87. package/dist/index.js.map +1 -0
  88. package/dist/index.mjs +2419 -0
  89. package/dist/index.mjs.map +1 -0
  90. package/dist/infrastructure/gateways/accounts.gateway.d.ts +30 -0
  91. package/dist/infrastructure/gateways/accounts.gateway.d.ts.map +1 -0
  92. package/dist/infrastructure/gateways/alcore-base.gateway.d.ts +45 -0
  93. package/dist/infrastructure/gateways/alcore-base.gateway.d.ts.map +1 -0
  94. package/dist/infrastructure/gateways/auth.gateway.d.ts +25 -0
  95. package/dist/infrastructure/gateways/auth.gateway.d.ts.map +1 -0
  96. package/dist/infrastructure/gateways/card-issuance.gateway.d.ts +23 -0
  97. package/dist/infrastructure/gateways/card-issuance.gateway.d.ts.map +1 -0
  98. package/dist/infrastructure/gateways/payment-instruments.gateway.d.ts +15 -0
  99. package/dist/infrastructure/gateways/payment-instruments.gateway.d.ts.map +1 -0
  100. package/dist/infrastructure/gateways/payments.gateway.d.ts +24 -0
  101. package/dist/infrastructure/gateways/payments.gateway.d.ts.map +1 -0
  102. package/dist/infrastructure/gateways/wallets.gateway.d.ts +12 -0
  103. package/dist/infrastructure/gateways/wallets.gateway.d.ts.map +1 -0
  104. package/dist/infrastructure/logging/logger.service.d.ts +52 -0
  105. package/dist/infrastructure/logging/logger.service.d.ts.map +1 -0
  106. package/dist/infrastructure/security/cryptor.service.d.ts +68 -0
  107. package/dist/infrastructure/security/cryptor.service.d.ts.map +1 -0
  108. package/dist/infrastructure/security/validator.service.d.ts +128 -0
  109. package/dist/infrastructure/security/validator.service.d.ts.map +1 -0
  110. package/dist/plugins/field-plugin-registry.d.ts +102 -0
  111. package/dist/plugins/field-plugin-registry.d.ts.map +1 -0
  112. package/dist/plugins/field-plugin.interface.d.ts +123 -0
  113. package/dist/plugins/field-plugin.interface.d.ts.map +1 -0
  114. package/dist/plugins/fields/card-number.plugin.d.ts +80 -0
  115. package/dist/plugins/fields/card-number.plugin.d.ts.map +1 -0
  116. package/dist/plugins/fields/cvv.plugin.d.ts +70 -0
  117. package/dist/plugins/fields/cvv.plugin.d.ts.map +1 -0
  118. package/dist/plugins/fields/expiry-date.plugin.d.ts +54 -0
  119. package/dist/plugins/fields/expiry-date.plugin.d.ts.map +1 -0
  120. package/dist/plugins/fields/text.plugin.d.ts +79 -0
  121. package/dist/plugins/fields/text.plugin.d.ts.map +1 -0
  122. package/dist/services/accounts-api.service.d.ts +28 -0
  123. package/dist/services/accounts-api.service.d.ts.map +1 -0
  124. package/dist/services/payment-instruments-api.service.d.ts +13 -0
  125. package/dist/services/payment-instruments-api.service.d.ts.map +1 -0
  126. package/dist/services/payment-processor.service.d.ts +43 -0
  127. package/dist/services/payment-processor.service.d.ts.map +1 -0
  128. package/dist/services/wallets-api.service.d.ts +10 -0
  129. package/dist/services/wallets-api.service.d.ts.map +1 -0
  130. package/package.json +54 -0
package/dist/index.mjs ADDED
@@ -0,0 +1,2419 @@
1
+ import { pki } from "node-forge";
2
+ class Logger {
3
+ /**
4
+ * Logger constructor.
5
+ *
6
+ * @param isDebug This is what enables/disables our output messages
7
+ */
8
+ constructor(isDebug) {
9
+ this.logger = "CORE_LOGGER";
10
+ this.isDebug = isDebug;
11
+ }
12
+ /**
13
+ * This is the method to output a debug message to console.
14
+ *
15
+ * @param msg The message to output to console
16
+ */
17
+ debug(msg) {
18
+ if (this.isDebug) {
19
+ if (typeof console.debug !== "undefined") {
20
+ console.debug(msg);
21
+ } else {
22
+ console.log(msg);
23
+ }
24
+ }
25
+ }
26
+ /**
27
+ * This is the method to output a warning message to console.
28
+ *
29
+ * @param msg The message to output to console
30
+ */
31
+ warning(msg) {
32
+ if (this.isDebug) {
33
+ if (typeof console.warn !== "undefined") {
34
+ console.warn(msg);
35
+ } else {
36
+ console.log(msg);
37
+ }
38
+ }
39
+ }
40
+ /**
41
+ * Alias for warning() for consistency with console API
42
+ *
43
+ * @param msg The message to output to console
44
+ */
45
+ warn(msg) {
46
+ this.warning(msg);
47
+ }
48
+ /**
49
+ * This is the method to output an info message to console.
50
+ *
51
+ * @param msg The message to output to console
52
+ */
53
+ info(msg) {
54
+ if (this.isDebug) {
55
+ if (typeof console.info !== "undefined") {
56
+ console.info(msg);
57
+ } else {
58
+ console.log(msg);
59
+ }
60
+ }
61
+ }
62
+ /**
63
+ * This is the method to output an error message to console.
64
+ *
65
+ * @param msg The message to output to console
66
+ */
67
+ error(msg) {
68
+ if (this.isDebug) {
69
+ if (typeof console.error !== "undefined") {
70
+ console.error(msg);
71
+ } else {
72
+ console.log(msg);
73
+ }
74
+ }
75
+ }
76
+ /**
77
+ * Check if debug mode is enabled
78
+ */
79
+ isDebugEnabled() {
80
+ return this.isDebug;
81
+ }
82
+ }
83
+ const DEFAULT_CONFIG = {
84
+ domain: "https://api.dev.alviere.com",
85
+ access_token: "",
86
+ certificate: {
87
+ id: "",
88
+ public_key: ""
89
+ }
90
+ };
91
+ let runtimeConfig = { ...DEFAULT_CONFIG };
92
+ function setRuntimeConfig(config) {
93
+ runtimeConfig = { ...runtimeConfig, ...config };
94
+ }
95
+ function getRuntimeConfig() {
96
+ return runtimeConfig;
97
+ }
98
+ function getEnvVar(key) {
99
+ if (typeof window !== "undefined" && window.VITE_DEBUG) {
100
+ const viteKey = `VITE_${key}`;
101
+ return window[viteKey];
102
+ }
103
+ return void 0;
104
+ }
105
+ function initializeFromEnvironment() {
106
+ if (runtimeConfig.domain && runtimeConfig.certificate) {
107
+ return;
108
+ }
109
+ const envConfig = {};
110
+ const envDomain = getEnvVar("ALVIERE_DOMAIN");
111
+ const envCertificate = getEnvVar("CERTIFICATE");
112
+ if (envDomain) envConfig.domain = envDomain;
113
+ if (envCertificate) {
114
+ try {
115
+ const cert = JSON.parse(envCertificate);
116
+ if (cert && typeof cert.id === "string" && typeof cert.public_key === "string") {
117
+ envConfig.certificate = { id: cert.id, public_key: cert.public_key };
118
+ }
119
+ } catch {
120
+ }
121
+ }
122
+ if (envConfig.domain || envConfig.certificate) {
123
+ setRuntimeConfig(envConfig);
124
+ }
125
+ }
126
+ const getALVIERE_DOMAIN = () => {
127
+ if (!runtimeConfig.domain) {
128
+ initializeFromEnvironment();
129
+ }
130
+ return runtimeConfig.domain;
131
+ };
132
+ const getRSA_PUB_KEY = () => {
133
+ if (!runtimeConfig.certificate) {
134
+ initializeFromEnvironment();
135
+ }
136
+ return runtimeConfig.certificate.public_key;
137
+ };
138
+ const getCERTIFICATE_ID = () => {
139
+ if (!runtimeConfig.certificate) {
140
+ initializeFromEnvironment();
141
+ }
142
+ return runtimeConfig.certificate.id;
143
+ };
144
+ const ALVIERE_DOMAIN = getALVIERE_DOMAIN();
145
+ const RSA_PUB_KEY = getRSA_PUB_KEY();
146
+ const CERTIFICATE_ID = getCERTIFICATE_ID();
147
+ class Cryptor {
148
+ /**
149
+ *
150
+ */
151
+ constructor(logger) {
152
+ this.logger = logger;
153
+ this.rsa_key = getRSA_PUB_KEY();
154
+ this.key = this.generate_key();
155
+ this.nonce = this.generate_nonce();
156
+ this.logger?.debug("🔐 Cryptor initialized");
157
+ }
158
+ /**
159
+ *
160
+ * @param data
161
+ * @returns
162
+ */
163
+ async encrypt(data) {
164
+ const encoded = new TextEncoder().encode(JSON.stringify(data));
165
+ const alg = { name: "AES-GCM", iv: this.nonce };
166
+ const crypto_key = await this.import_key();
167
+ const cipher = await crypto.subtle.encrypt(alg, crypto_key, encoded);
168
+ const cipherStr = this.bufferToStr(cipher);
169
+ const cipherB64 = btoa(cipherStr);
170
+ const keyStr = this.bufferToStr(this.key);
171
+ const keyB64 = btoa(keyStr);
172
+ const nonceStr = this.bufferToStr(this.nonce);
173
+ const nonceB64 = btoa(nonceStr);
174
+ this.logger?.debug(`🔐 RSA_KEY: ${this.rsa_key.substring(0, 50)}...`);
175
+ const publicKey = pki.publicKeyFromPem(this.rsa_key);
176
+ const keyNonceCipher = publicKey.encrypt(keyB64 + "::" + nonceB64);
177
+ const keyNonceB64 = btoa(keyNonceCipher);
178
+ const encrypted_request = {
179
+ p: cipherB64,
180
+ // base64(AES-GCM(<sdk_envelope>))
181
+ k: keyNonceB64,
182
+ // base64(RSA(base64(SDK_KEY)::base64(<sdk_nonce>)))
183
+ i: getCERTIFICATE_ID()
184
+ // certificate id - configurable via environment variable
185
+ };
186
+ this.logger?.debug(
187
+ `🔐 ENCRYPTED_REQUEST: p=${encrypted_request.p.substring(0, 20)}..., i=${encrypted_request.i}`
188
+ );
189
+ return encrypted_request;
190
+ }
191
+ /**
192
+ *
193
+ * @param data
194
+ * @returns
195
+ */
196
+ async decrypt(data) {
197
+ const decrypted = await crypto.subtle.decrypt(
198
+ { name: "AES-GCM", iv: this.nonce },
199
+ await this.import_key(),
200
+ Uint8Array.from(atob(data.p), (c) => c.charCodeAt(0))
201
+ );
202
+ const decryptedText = new TextDecoder().decode(decrypted);
203
+ this.logger?.debug(`🔐 DECRYPTED: ${decryptedText}`);
204
+ return JSON.parse(decryptedText);
205
+ }
206
+ /**
207
+ *
208
+ * @returns
209
+ */
210
+ generate_key() {
211
+ return crypto.getRandomValues(new Uint8Array(32));
212
+ }
213
+ /**
214
+ *
215
+ * @returns
216
+ */
217
+ generate_nonce() {
218
+ return crypto.getRandomValues(new Uint8Array(12));
219
+ }
220
+ /**
221
+ *
222
+ * @returns
223
+ */
224
+ async import_key() {
225
+ return await crypto.subtle.importKey("raw", this.key, { name: "AES-GCM" }, true, [
226
+ "encrypt",
227
+ "decrypt"
228
+ ]);
229
+ }
230
+ /**
231
+ *
232
+ * @param data
233
+ * @returns
234
+ */
235
+ async rsa_encrypt(data) {
236
+ this.logger?.debug(`🔐 RSA_ENCRYPT: Data to encrypt: ${data.substring(0, 50)}...`);
237
+ this.logger?.debug(`🔐 RSA_KEY: ${this.rsa_key.substring(0, 50)}...`);
238
+ const publicKey = pki.publicKeyFromPem(this.rsa_key);
239
+ return btoa(publicKey.encrypt(data));
240
+ }
241
+ /**
242
+ *
243
+ * @param buf
244
+ */
245
+ bufferToStr(buf) {
246
+ const cb = Array.from(new Uint8Array(buf));
247
+ const cs = cb.map((byte) => String.fromCharCode(byte)).join("");
248
+ return cs;
249
+ }
250
+ }
251
+ class Validator {
252
+ /**
253
+ *
254
+ * @param logger
255
+ */
256
+ constructor(logger) {
257
+ this.logger = logger;
258
+ }
259
+ /**
260
+ *
261
+ * @param name
262
+ */
263
+ credit_card_name(name) {
264
+ this.logger.debug(`🔐 CREDIT_CARD_NAME: ${name}`);
265
+ if (!name || typeof name !== "string") {
266
+ return "Card holder name cannot be empty.";
267
+ }
268
+ if (name.trim().length === 0) {
269
+ return "Card holder name cannot be empty.";
270
+ }
271
+ return null;
272
+ }
273
+ /**
274
+ *
275
+ * @param number
276
+ */
277
+ credit_card_number(number) {
278
+ if (!number || typeof number !== "string") {
279
+ return "Please enter a valid card number.";
280
+ }
281
+ const visaRegEx = /^(?:4[0-9]{12}(?:[0-9]{3})?)$/;
282
+ const mastercardRegEx = /^(?:5[1-5][0-9]{14})$/;
283
+ const amexpRegEx = /^(?:3[47][0-9]{13})$/;
284
+ const discovRegEx = /^(?:6(?:011|5[0-9][0-9])[0-9]{12})$/;
285
+ if (visaRegEx.test(number.replace(/\s/g, ""))) {
286
+ return null;
287
+ } else if (mastercardRegEx.test(number.replace(/\s/g, ""))) {
288
+ return null;
289
+ } else if (amexpRegEx.test(number.replace(/\s/g, ""))) {
290
+ return null;
291
+ } else if (discovRegEx.test(number.replace(/\s/g, ""))) {
292
+ return null;
293
+ }
294
+ this.logger.debug("🔐 card number is not a recognized brand");
295
+ return "Please enter a valid card number.";
296
+ }
297
+ /**
298
+ *
299
+ * @param expiry
300
+ */
301
+ credit_card_expiry_date(expiry) {
302
+ if (!expiry || typeof expiry !== "string") {
303
+ return "Expiry date cannot be empty.";
304
+ }
305
+ if (expiry.trim().length === 0) {
306
+ return "Expiry date cannot be empty.";
307
+ }
308
+ const expiryRegEx = /^(0[1-9]|1[0-2])\/?([0-9]{4}|[0-9]{2})$/;
309
+ if (!expiryRegEx.test(expiry)) {
310
+ return "Please enter a valid expiry date.";
311
+ }
312
+ return null;
313
+ }
314
+ /**
315
+ *
316
+ * @param code
317
+ */
318
+ credit_card_sec_code(code) {
319
+ if (!code || typeof code !== "string") {
320
+ return "Security code cannot be empty.";
321
+ }
322
+ if (code.trim().length === 0) {
323
+ return "Security code cannot be empty.";
324
+ }
325
+ const secCodeRegEx = /^[0-9]{3,4}$/;
326
+ if (!secCodeRegEx.test(code)) {
327
+ return "Please enter a valid security code.";
328
+ }
329
+ return null;
330
+ }
331
+ /**
332
+ *
333
+ * @param zip
334
+ */
335
+ credit_card_zip_code(zip) {
336
+ if (!zip || typeof zip !== "string") {
337
+ return "Zip code cannot be empty.";
338
+ }
339
+ if (zip.trim().length === 0) {
340
+ return "Zip code cannot be empty.";
341
+ }
342
+ return null;
343
+ }
344
+ /**
345
+ *
346
+ * @param pin
347
+ */
348
+ credit_card_pin(pin) {
349
+ if (!pin || typeof pin !== "string") {
350
+ return "PIN cannot be empty.";
351
+ }
352
+ if (pin.trim().length === 0) {
353
+ return "PIN cannot be empty.";
354
+ }
355
+ const pinRegEx = /^[0-9]{4}$/;
356
+ if (!pinRegEx.test(pin)) {
357
+ return "Please enter a valid PIN.";
358
+ }
359
+ return null;
360
+ }
361
+ /**
362
+ *
363
+ * @param uuid
364
+ */
365
+ is_valid_uuid(uuid) {
366
+ if (!uuid || typeof uuid !== "string") {
367
+ return "UUID cannot be empty.";
368
+ }
369
+ if (uuid.trim().length === 0) {
370
+ return "UUID cannot be empty.";
371
+ }
372
+ const uuidRegEx = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
373
+ if (!uuidRegEx.test(uuid)) {
374
+ return "Please enter a valid UUID.";
375
+ }
376
+ return null;
377
+ }
378
+ /**
379
+ * Validates that a field is not empty or null
380
+ * @param value - The value to validate
381
+ * @param fieldName - Optional field name for error message
382
+ */
383
+ required(value, fieldName) {
384
+ if (value === null || value === void 0 || typeof value === "string" && value.trim().length === 0) {
385
+ return fieldName ? `${fieldName} is required.` : "This field is required.";
386
+ }
387
+ return null;
388
+ }
389
+ /**
390
+ * Validates email address format
391
+ * @param email - The email to validate
392
+ */
393
+ email(email) {
394
+ if (!email || typeof email !== "string") {
395
+ return "Please enter a valid email address.";
396
+ }
397
+ const trimmed = email.trim();
398
+ if (trimmed.includes("..")) {
399
+ return "Please enter a valid email address.";
400
+ }
401
+ const emailRegEx = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+$/;
402
+ if (!emailRegEx.test(trimmed)) {
403
+ return "Please enter a valid email address.";
404
+ }
405
+ return null;
406
+ }
407
+ /**
408
+ * Validates phone number format
409
+ * @param phone - The phone number to validate
410
+ */
411
+ phone(phone) {
412
+ if (!phone || typeof phone !== "string") {
413
+ return "Please enter a valid phone number.";
414
+ }
415
+ if (!phone.startsWith("+")) {
416
+ return "Phone number must start with country code (e.g., +1)";
417
+ }
418
+ const afterPlus = phone.substring(1);
419
+ const countryCodeMatch = afterPlus.match(/^(\d{1,3})/);
420
+ if (!countryCodeMatch) {
421
+ return "Invalid country code format";
422
+ }
423
+ const countryCode = countryCodeMatch[1];
424
+ const phoneNumber = afterPlus.substring(countryCode.length);
425
+ if (phoneNumber.length < 7) {
426
+ return "Phone number too short";
427
+ }
428
+ const totalDigits = countryCode.length + phoneNumber.length;
429
+ if (totalDigits < 10 || totalDigits > 15) {
430
+ return "Phone number must be between 10 and 15 digits total";
431
+ }
432
+ return null;
433
+ }
434
+ /**
435
+ * Validates date format and calendar validity
436
+ * @param date - The date string to validate
437
+ * @param format - The expected date format (default: 'YYYY-MM-DD')
438
+ */
439
+ date(date, format = "YYYY-MM-DD") {
440
+ if (!date || typeof date !== "string") {
441
+ return "Please enter a valid date.";
442
+ }
443
+ const dateRegex = /^([0-9]{4})-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])$/;
444
+ if (!dateRegex.test(date)) {
445
+ return "Please enter a valid date in YYYY-MM-DD format";
446
+ }
447
+ const [, yearStr, monthStr, dayStr] = date.match(dateRegex) || [];
448
+ const year = parseInt(yearStr);
449
+ const month = parseInt(monthStr);
450
+ const day = parseInt(dayStr);
451
+ if (!this.isValidCalendarDate(year, month, day)) {
452
+ return "Invalid date - this date does not exist";
453
+ }
454
+ const dateObj = new Date(date);
455
+ const now = /* @__PURE__ */ new Date();
456
+ const minDate = /* @__PURE__ */ new Date("1900-01-01");
457
+ if (dateObj > now) {
458
+ return "Date cannot be in the future";
459
+ }
460
+ if (dateObj < minDate) {
461
+ return "Date cannot be before 1900";
462
+ }
463
+ return null;
464
+ }
465
+ /**
466
+ * Helper function to validate calendar dates
467
+ * @param year - The year
468
+ * @param month - The month (1-12)
469
+ * @param day - The day (1-31)
470
+ */
471
+ isValidCalendarDate(year, month, day) {
472
+ const date = new Date(year, month - 1, day);
473
+ return date.getFullYear() === year && date.getMonth() === month - 1 && date.getDate() === day;
474
+ }
475
+ /**
476
+ * Validates minimum length
477
+ * @param value - The value to validate
478
+ * @param minLength - Minimum required length
479
+ * @param fieldName - Optional field name for error message
480
+ */
481
+ min_length(value, minLength, fieldName) {
482
+ if (!value || typeof value !== "string") {
483
+ return fieldName ? `${fieldName} is required.` : "This field is required.";
484
+ }
485
+ if (value.length < minLength) {
486
+ return fieldName ? `${fieldName} must be at least ${minLength} characters long.` : `Must be at least ${minLength} characters long.`;
487
+ }
488
+ return null;
489
+ }
490
+ /**
491
+ * Validates maximum length
492
+ * @param value - The value to validate
493
+ * @param maxLength - Maximum allowed length
494
+ * @param fieldName - Optional field name for error message
495
+ */
496
+ max_length(value, maxLength, fieldName) {
497
+ if (value && typeof value === "string" && value.length > maxLength) {
498
+ return fieldName ? `${fieldName} must be no more than ${maxLength} characters long.` : `Must be no more than ${maxLength} characters long.`;
499
+ }
500
+ return null;
501
+ }
502
+ /**
503
+ * Validates against a custom pattern
504
+ * @param value - The value to validate
505
+ * @param pattern - RegExp pattern to match
506
+ * @param errorMessage - Custom error message
507
+ */
508
+ pattern(value, pattern, errorMessage) {
509
+ if (!value || typeof value !== "string") {
510
+ return errorMessage || "Please enter a valid value.";
511
+ }
512
+ if (!pattern.test(value)) {
513
+ return errorMessage || "Please enter a valid value.";
514
+ }
515
+ return null;
516
+ }
517
+ /**
518
+ * Validates that a value contains only numbers
519
+ * @param value - The value to validate
520
+ * @param fieldName - Optional field name for error message
521
+ */
522
+ numeric(value, fieldName) {
523
+ if (!value || typeof value !== "string") {
524
+ return fieldName ? `${fieldName} is required.` : "This field is required.";
525
+ }
526
+ if (!/^\d+$/.test(value.trim())) {
527
+ return fieldName ? `${fieldName} must contain only numbers.` : "Must contain only numbers.";
528
+ }
529
+ return null;
530
+ }
531
+ /**
532
+ * Validates that a value contains only letters
533
+ * @param value - The value to validate
534
+ * @param fieldName - Optional field name for error message
535
+ */
536
+ alphabetic(value, fieldName) {
537
+ if (!value || typeof value !== "string") {
538
+ return fieldName ? `${fieldName} is required.` : "This field is required.";
539
+ }
540
+ if (!/^[a-zA-Z\s]+$/.test(value.trim())) {
541
+ return fieldName ? `${fieldName} must contain only letters and spaces.` : "Must contain only letters and spaces.";
542
+ }
543
+ return null;
544
+ }
545
+ /**
546
+ * Validates that a value contains only letters and numbers
547
+ * @param value - The value to validate
548
+ * @param fieldName - Optional field name for error message
549
+ */
550
+ alphanumeric(value, fieldName) {
551
+ if (!value || typeof value !== "string") {
552
+ return fieldName ? `${fieldName} is required.` : "This field is required.";
553
+ }
554
+ if (!/^[a-zA-Z0-9\s]+$/.test(value.trim())) {
555
+ return fieldName ? `${fieldName} must contain only letters, numbers, and spaces.` : "Must contain only letters, numbers, and spaces.";
556
+ }
557
+ return null;
558
+ }
559
+ /**
560
+ * Validates URL format
561
+ * @param url - The URL to validate
562
+ */
563
+ url(url) {
564
+ if (!url || typeof url !== "string") {
565
+ return "Please enter a valid URL.";
566
+ }
567
+ const trimmed = url.trim();
568
+ try {
569
+ const urlObj = new URL(trimmed);
570
+ if (urlObj.hostname === "" || urlObj.hostname.startsWith(".") || urlObj.hostname.endsWith(".")) {
571
+ return "Please enter a valid URL.";
572
+ }
573
+ return null;
574
+ } catch {
575
+ return "Please enter a valid URL.";
576
+ }
577
+ }
578
+ /**
579
+ * Validates postal code based on country
580
+ * @param code - The postal code to validate
581
+ * @param country - Country code (default: US)
582
+ */
583
+ postal_code(code, country = "US") {
584
+ if (!code || typeof code !== "string") {
585
+ return "Please enter a valid postal code.";
586
+ }
587
+ const cleanCode = code.trim();
588
+ switch (country.toUpperCase()) {
589
+ case "US":
590
+ if (!/^\d{5}(-\d{4})?$/.test(cleanCode)) {
591
+ return "Please enter a valid US ZIP code (e.g., 12345 or 12345-6789).";
592
+ }
593
+ break;
594
+ case "CA":
595
+ if (!/^[A-Za-z]\d[A-Za-z] \d[A-Za-z]\d$/.test(cleanCode)) {
596
+ return "Please enter a valid Canadian postal code (e.g., A1A 1A1).";
597
+ }
598
+ break;
599
+ case "UK":
600
+ case "GB":
601
+ if (!/^[A-Za-z]{1,2}\d[A-Za-z\d]?\s\d[A-Za-z]{2}$/.test(cleanCode)) {
602
+ return "Please enter a valid UK postal code (e.g., SW1A 1AA).";
603
+ }
604
+ break;
605
+ default:
606
+ if (!/^[A-Za-z0-9\s-]{3,10}$/.test(cleanCode)) {
607
+ return "Please enter a valid postal code.";
608
+ }
609
+ }
610
+ return null;
611
+ }
612
+ }
613
+ class AlcoreApiError extends Error {
614
+ constructor(errorCode, errorDescription, statusCode) {
615
+ super(`Alcore API Error ${errorCode}: ${errorDescription}`);
616
+ this.name = "AlcoreApiError";
617
+ this.errorCode = errorCode;
618
+ this.errorDescription = errorDescription;
619
+ this.statusCode = statusCode;
620
+ if (Error.captureStackTrace) {
621
+ Error.captureStackTrace(this, AlcoreApiError);
622
+ }
623
+ }
624
+ /**
625
+ * Check if error matches a specific error code
626
+ */
627
+ isErrorCode(code) {
628
+ return this.errorCode === code;
629
+ }
630
+ /**
631
+ * Check if error matches any of the provided error codes
632
+ */
633
+ isAnyErrorCode(codes) {
634
+ return codes.includes(this.errorCode);
635
+ }
636
+ }
637
+ const AlcoreErrorCodes = {
638
+ ALVIERE_CORE_NOT_INITIALIZED: "000000",
639
+ // Authentication errors (100xxx)
640
+ UNPROCESSABLE_ENCRYPTED_DATA: "100011",
641
+ WRONG_ENCRYPTED_ENDPOINT: "100012",
642
+ UNDECRYPTABLE_DATA_AT_ENDPOINT: "100013",
643
+ DECRYPTED_DATA_UNUSABLE_AT_ENDPOINT: "100014",
644
+ WRONG_DECRYPTED_ENDPOINT: "100015",
645
+ WRONG_VERSION_OR_ENDPOINT: "100016",
646
+ OPERATION_HALTED: "100017",
647
+ INVALID_REQUEST_PAYLOAD: "100300",
648
+ INVALID_REQUEST_PAYLOAD_FIELD: "100301",
649
+ INVALID_PATH_PARAMETER: "100302",
650
+ INVALID_HEADER: "100303",
651
+ INVALID_QUERY_PARAMETER: "100304",
652
+ INVALID_JWT: "100305",
653
+ AUTH_FAILED: "100306",
654
+ SESSION_NOT_FOUND: "110000",
655
+ PARENT_ACCOUNT_NOT_FOUND: "110001",
656
+ NOT_FOUND: "110002",
657
+ ACCOUNT_TYPE_NOT_SUPPORTED: "110004",
658
+ UNDERLYING_API_ERROR: "115000",
659
+ ACCOUNT_STATUS_NOT_ACTIVE: "115001",
660
+ ACCOUNT_CHILD_FORBIDDEN: "320129",
661
+ PARENT_ACCOUNT_NOT_ALLOWED: "320104"
662
+ // Add more error codes as you discover them from the API
663
+ };
664
+ const AlcoreErrorMessages = {
665
+ [AlcoreErrorCodes.INVALID_JWT]: "Invalid authentication token. Please log in again.",
666
+ [AlcoreErrorCodes.AUTH_FAILED]: "Authentication failed. Please check your credentials and try again.",
667
+ [AlcoreErrorCodes.SESSION_NOT_FOUND]: "Session not found. Please log in again.",
668
+ [AlcoreErrorCodes.PARENT_ACCOUNT_NOT_FOUND]: "Parent account not found.",
669
+ [AlcoreErrorCodes.NOT_FOUND]: "Resource not found.",
670
+ [AlcoreErrorCodes.ACCOUNT_TYPE_NOT_SUPPORTED]: "Account type not supported.",
671
+ [AlcoreErrorCodes.INVALID_REQUEST_PAYLOAD]: "Invalid request payload. Please check your request and try again.",
672
+ [AlcoreErrorCodes.INVALID_REQUEST_PAYLOAD_FIELD]: "Invalid request payload field. Please check your request and try again.",
673
+ [AlcoreErrorCodes.INVALID_PATH_PARAMETER]: "Invalid path parameter. Please check your request and try again.",
674
+ [AlcoreErrorCodes.INVALID_HEADER]: "Invalid header. Please check your request and try again.",
675
+ [AlcoreErrorCodes.INVALID_QUERY_PARAMETER]: "Invalid query parameter. Please check your request and try again.",
676
+ [AlcoreErrorCodes.UNPROCESSABLE_ENCRYPTED_DATA]: "Unprocessable encrypted data. Please check your request and try again.",
677
+ [AlcoreErrorCodes.WRONG_ENCRYPTED_ENDPOINT]: "Wrong encrypted endpoint. Please check your request and try again.",
678
+ [AlcoreErrorCodes.UNDECRYPTABLE_DATA_AT_ENDPOINT]: "Undecryptable data at endpoint. Please check your request and try again.",
679
+ [AlcoreErrorCodes.DECRYPTED_DATA_UNUSABLE_AT_ENDPOINT]: "Decrypted data unusable at endpoint. Please check your request and try again.",
680
+ [AlcoreErrorCodes.WRONG_DECRYPTED_ENDPOINT]: "Wrong decrypted endpoint. Please check your request and try again.",
681
+ [AlcoreErrorCodes.WRONG_VERSION_OR_ENDPOINT]: "Wrong version or endpoint. Please check your request and try again.",
682
+ [AlcoreErrorCodes.OPERATION_HALTED]: "Operation halted. Please check your request and try again.",
683
+ [AlcoreErrorCodes.UNDERLYING_API_ERROR]: "Underlying API Error. ",
684
+ [AlcoreErrorCodes.ACCOUNT_STATUS_NOT_ACTIVE]: "Account status not active. Please check your request and try again.",
685
+ [AlcoreErrorCodes.ACCOUNT_CHILD_FORBIDDEN]: "Used Account can't be used to create a child account.",
686
+ [AlcoreErrorCodes.PARENT_ACCOUNT_NOT_ALLOWED]: "Parent account not allowed. Please check your request and try again."
687
+ };
688
+ function getErrorMessage(errorCode) {
689
+ return AlcoreErrorMessages[errorCode] || "An unexpected error occurred. Please try again.";
690
+ }
691
+ const CriticalErrorCodes = [
692
+ AlcoreErrorCodes.INVALID_JWT,
693
+ AlcoreErrorCodes.AUTH_FAILED,
694
+ AlcoreErrorCodes.SESSION_NOT_FOUND,
695
+ AlcoreErrorCodes.UNPROCESSABLE_ENCRYPTED_DATA,
696
+ AlcoreErrorCodes.WRONG_ENCRYPTED_ENDPOINT,
697
+ AlcoreErrorCodes.UNDECRYPTABLE_DATA_AT_ENDPOINT,
698
+ AlcoreErrorCodes.OPERATION_HALTED,
699
+ AlcoreErrorCodes.ALVIERE_CORE_NOT_INITIALIZED,
700
+ AlcoreErrorCodes.UNDERLYING_API_ERROR,
701
+ AlcoreErrorCodes.ACCOUNT_STATUS_NOT_ACTIVE,
702
+ AlcoreErrorCodes.ACCOUNT_CHILD_FORBIDDEN,
703
+ AlcoreErrorCodes.PARENT_ACCOUNT_NOT_ALLOWED
704
+ ];
705
+ function isCriticalError(errorCode) {
706
+ return CriticalErrorCodes.includes(errorCode);
707
+ }
708
+ class AlcoreBase {
709
+ /**
710
+ *
711
+ * @param jwt
712
+ * @param cryptor
713
+ * @param logger
714
+ */
715
+ constructor(jwt, cryptor, logger) {
716
+ this.endpoint = "/alcore";
717
+ this.jwt = jwt;
718
+ this.cryptor = cryptor;
719
+ this.domain = getALVIERE_DOMAIN();
720
+ this.logger = logger;
721
+ this.logger.debug(`🔐 AlcoreBase initialized with domain: ${this.domain}`);
722
+ }
723
+ /**
724
+ * send
725
+ */
726
+ async send(method, endpoint, payload) {
727
+ const request = {
728
+ method,
729
+ endpoint,
730
+ payload: JSON.stringify(payload)
731
+ };
732
+ this.logger.debug("🌐 AlcoreBase: Preparing to send request");
733
+ this.logger.debug("🌐 Method: " + method);
734
+ this.logger.debug("🌐 Endpoint: " + endpoint);
735
+ this.logger.debug("🌐 Domain: " + (this.domain || "undefined"));
736
+ this.logger.debug("🌐 JWT Token: " + (this.jwt ? "✅ Present" : "❌ Missing"));
737
+ this.logger.debug("🌐 Payload size: " + JSON.stringify(payload).length + " chars");
738
+ this.logger.debug(this.jwt);
739
+ this.logger.debug("DATA TO SEND before encrypt");
740
+ this.logger.debug(payload);
741
+ let encryptedData;
742
+ try {
743
+ encryptedData = await this.cryptor.encrypt(request);
744
+ this.logger.debug("🔐 Encryption successful");
745
+ } catch (encryptError) {
746
+ this.logger.debug(
747
+ "❌ Encryption failed: " + (encryptError instanceof Error ? encryptError.message : "Unknown error")
748
+ );
749
+ throw encryptError;
750
+ }
751
+ this.logger.debug("BASE GATEWAY: posting to " + this.endpoint);
752
+ this.logger.debug(encryptedData);
753
+ const url = this.domain + this.endpoint;
754
+ this.logger.debug("🌐 Full URL: " + url);
755
+ try {
756
+ const response = await fetch(url, {
757
+ method: "post",
758
+ headers: {
759
+ "Content-Type": "application/json",
760
+ Authorization: "Bearer " + this.jwt,
761
+ Version: "2021-11-18"
762
+ },
763
+ body: JSON.stringify(encryptedData)
764
+ });
765
+ this.logger.debug(
766
+ "🌐 Response received - Status: " + response.status + " " + response.statusText
767
+ );
768
+ this.logger.debug("🌐 Response OK: " + response.ok);
769
+ if (!response.ok) {
770
+ let error = await response.json();
771
+ if (error.p) {
772
+ error = await this.decrypt(error);
773
+ }
774
+ this.logger.debug(
775
+ "❌ API Error - Code: " + error.error_code + ", Description: " + error.error_description
776
+ );
777
+ throw new AlcoreApiError(
778
+ response.status === 500 ? AlcoreErrorCodes.UNDERLYING_API_ERROR : error.error_code,
779
+ AlcoreErrorMessages[error.error_code],
780
+ response.status
781
+ );
782
+ }
783
+ return response;
784
+ } catch (fetchError) {
785
+ this.logger.debug(
786
+ "❌ Fetch failed: " + (fetchError instanceof Error ? fetchError.message : "Unknown error")
787
+ );
788
+ throw fetchError;
789
+ }
790
+ }
791
+ /**
792
+ *
793
+ * @param data
794
+ */
795
+ async decrypt(data) {
796
+ return this.cryptor.decrypt(data);
797
+ }
798
+ }
799
+ function getSanitizedBody(data) {
800
+ const body = {};
801
+ for (const key in data) {
802
+ if (Object.prototype.hasOwnProperty.call(data, key)) {
803
+ const value = data[key];
804
+ if (!["", null, void 0].includes(value)) {
805
+ body[key] = value;
806
+ }
807
+ }
808
+ }
809
+ return body;
810
+ }
811
+ function throwIfApiError(decrypted) {
812
+ if (decrypted && typeof decrypted === "object" && ("error_code" in decrypted || "error_description" in decrypted)) {
813
+ const errorMessage = decrypted.error_description || "Unknown API error";
814
+ const errorCode = decrypted.error_code || "UNKNOWN";
815
+ throw new Error(`${errorCode}: ${errorMessage}`);
816
+ }
817
+ return decrypted;
818
+ }
819
+ function decodeJWTPayload(jwt) {
820
+ try {
821
+ const parts = jwt.split(".");
822
+ if (parts.length !== 3) {
823
+ return null;
824
+ }
825
+ const payload = parts[1];
826
+ const decoded = atob(payload.replace(/-/g, "+").replace(/_/g, "/"));
827
+ return JSON.parse(decoded);
828
+ } catch (error) {
829
+ console.warn("Failed to decode JWT payload:", error);
830
+ return null;
831
+ }
832
+ }
833
+ function extractAlviereConfigFromJWT(jwt) {
834
+ const payload = decodeJWTPayload(jwt);
835
+ if (!payload) {
836
+ return {};
837
+ }
838
+ return {
839
+ domain: payload.api_domain || "https://api.dev.alviere.com"
840
+ };
841
+ }
842
+ function extractAccountUuidFromJWT(jwt) {
843
+ const payload = decodeJWTPayload(jwt);
844
+ if (!payload) {
845
+ return null;
846
+ }
847
+ return payload.sub || null;
848
+ }
849
+ function isJWTExpired(jwt) {
850
+ const payload = decodeJWTPayload(jwt);
851
+ if (!payload || !payload.exp) {
852
+ return true;
853
+ }
854
+ const now = Math.floor(Date.now() / 1e3);
855
+ return payload.exp < now;
856
+ }
857
+ function getJWTExpiration(jwt) {
858
+ const payload = decodeJWTPayload(jwt);
859
+ if (!payload || !payload.exp) {
860
+ return null;
861
+ }
862
+ return new Date(payload.exp * 1e3);
863
+ }
864
+ class PaymentsGateway extends AlcoreBase {
865
+ /**
866
+ *
867
+ * @param jwt
868
+ * @param cryptor
869
+ */
870
+ constructor(jwt, cryptor, logger) {
871
+ super(jwt, cryptor, logger);
872
+ }
873
+ async add_card(accountUuid, data) {
874
+ const endpoint = `/accounts/${accountUuid}/payment-methods/cards`;
875
+ const response = await this.send("POST", endpoint, data);
876
+ const encrypted = await response.json();
877
+ const decrypted = await this.decrypt(encrypted);
878
+ return throwIfApiError(decrypted);
879
+ }
880
+ async add_bank_account(accountUuid, data) {
881
+ const endpoint = `/accounts/${accountUuid}/payment-methods/bank-accounts`;
882
+ const response = await this.send("POST", endpoint, data);
883
+ const encrypted = await response.json();
884
+ const decrypted = await this.decrypt(encrypted);
885
+ return throwIfApiError(decrypted);
886
+ }
887
+ async get_bank_accounts(accountUuid) {
888
+ const endpoint = `/accounts/${accountUuid}/payment-methods/bank-accounts`;
889
+ const response = await this.send("GET", endpoint, {});
890
+ const encrypted = await response.json();
891
+ const decrypted = await this.decrypt(encrypted);
892
+ return throwIfApiError(decrypted);
893
+ }
894
+ async delete_bank_account(accountUuid, uuid) {
895
+ const endpoint = `/accounts/${accountUuid}/payment-methods/bank-accounts/${uuid}`;
896
+ const response = await this.send("DELETE", endpoint, {});
897
+ return throwIfApiError(response);
898
+ }
899
+ }
900
+ class WalletsGateway extends AlcoreBase {
901
+ constructor(jwt, cryptor, logger) {
902
+ super(jwt, cryptor, logger);
903
+ }
904
+ async listWallets(accountUuid, params) {
905
+ const query = params ? "?" + new URLSearchParams(
906
+ Object.entries(params).filter(([_, v]) => v !== void 0)
907
+ ) : "";
908
+ const endpoint = `/accounts/${accountUuid}/wallets${query}`;
909
+ const response = await this.send("GET", endpoint, {});
910
+ const encrypted = await response.json();
911
+ const decrypted = await this.decrypt(encrypted);
912
+ return throwIfApiError(decrypted);
913
+ }
914
+ // async getWallet(accountUuid: string, walletUuid: string): Promise<WalletResponse> {
915
+ // throw new Error('getWallet not implemented');
916
+ // }
917
+ async loadFunds(walletUuid, data) {
918
+ const endpoint = `/wallets/${walletUuid}/load`;
919
+ const response = await this.send("POST", endpoint, data);
920
+ const encrypted = await response.json();
921
+ const decrypted = await this.decrypt(encrypted);
922
+ return throwIfApiError(decrypted);
923
+ }
924
+ // async withdrawFunds(walletUuid: string, data: WithdrawFundsRequest): Promise<WalletTransactionResponse> {
925
+ // throw new Error('withdrawFunds not implemented');
926
+ // }
927
+ // async sendFunds(walletUuid: string, data: SendFundsRequest): Promise<WalletTransactionResponse> {
928
+ // throw new Error('sendFunds not implemented');
929
+ // }
930
+ // async transferFunds(walletUuid: string, data: TransferFundsRequest): Promise<WalletTransactionResponse> {
931
+ // throw new Error('transferFunds not implemented');
932
+ // }
933
+ // async creditFunds(walletUuid: string, data: CreditFundsRequest): Promise<WalletTransactionResponse> {
934
+ // throw new Error('creditFunds not implemented');
935
+ // }
936
+ // async creditPromoFunds(walletUuid: string, data: PromoFundsRequest): Promise<WalletTransactionResponse> {
937
+ // throw new Error('creditPromoFunds not implemented');
938
+ // }
939
+ // async getWalletStatement(walletUuid: string, monthYear: string, scope?: 'DEBITS' | 'CREDITS' | 'FEES' | 'ALL'): Promise<WalletStatementResponse> {
940
+ // throw new Error('getWalletStatement not implemented');
941
+ // }
942
+ }
943
+ class PaymentInstrumentsGateway extends AlcoreBase {
944
+ constructor(jwt, cryptor, logger) {
945
+ super(jwt, cryptor, logger);
946
+ }
947
+ async createPaymentInstrument(data) {
948
+ const endpoint = "/payments/payment-instruments";
949
+ const response = await this.send("POST", endpoint, data);
950
+ const encrypted = await response.json();
951
+ const decrypted = await this.decrypt(encrypted);
952
+ return throwIfApiError(decrypted);
953
+ }
954
+ async getPaymentInstrument(paymentInstrumentUuid) {
955
+ const endpoint = `/payments/payment-instruments/${paymentInstrumentUuid}`;
956
+ const response = await this.send("GET", endpoint, {});
957
+ const encrypted = await response.json();
958
+ const decrypted = await this.decrypt(encrypted);
959
+ return throwIfApiError(decrypted);
960
+ }
961
+ async deletePaymentInstrument(paymentInstrumentUuid) {
962
+ const endpoint = `/payments/payment-instruments/${paymentInstrumentUuid}`;
963
+ await this.send("DELETE", endpoint, {});
964
+ }
965
+ async debitFunds(data) {
966
+ const endpoint = "/payments/debit";
967
+ const response = await this.send("POST", endpoint, data);
968
+ const encrypted = await response.json();
969
+ const decrypted = await this.decrypt(encrypted);
970
+ return throwIfApiError(decrypted);
971
+ }
972
+ async listCards(accountUuid, params) {
973
+ const query = params ? "?" + new URLSearchParams(Object.entries(params).filter(([_, v]) => v !== void 0)) : "";
974
+ const endpoint = `/accounts/${accountUuid}/payment-methods/cards${query}`;
975
+ const response = await this.send("GET", endpoint, {});
976
+ const encrypted = await response.json();
977
+ const decrypted = await this.decrypt(encrypted);
978
+ return throwIfApiError(decrypted);
979
+ }
980
+ }
981
+ class AccountsGateway extends AlcoreBase {
982
+ constructor(jwt, cryptor, logger) {
983
+ super(jwt, cryptor, logger);
984
+ this.logger.debug("🔐 AccountsGateway initialized");
985
+ }
986
+ async createAccount(data) {
987
+ const endpoint = "/accounts";
988
+ const response = await this.send("POST", endpoint, data);
989
+ const encrypted = await response.json();
990
+ const decrypted = await this.decrypt(encrypted);
991
+ return throwIfApiError(decrypted);
992
+ }
993
+ async getAccount(accountUuid) {
994
+ const endpoint = `/accounts/${accountUuid}`;
995
+ const response = await this.send("GET", endpoint, {});
996
+ const encrypted = await response.json();
997
+ const decrypted = await this.decrypt(encrypted);
998
+ return throwIfApiError(decrypted);
999
+ }
1000
+ async updateAccount(accountUuid, data) {
1001
+ const endpoint = `/accounts/${accountUuid}`;
1002
+ const response = await this.send("PUT", endpoint, data);
1003
+ const encrypted = await response.json();
1004
+ const decrypted = await this.decrypt(encrypted);
1005
+ return throwIfApiError(decrypted);
1006
+ }
1007
+ async deleteAccount(accountUuid) {
1008
+ const endpoint = `/accounts/${accountUuid}`;
1009
+ await this.send("DELETE", endpoint, {});
1010
+ }
1011
+ async listAccounts(params) {
1012
+ const query = params ? "?" + new URLSearchParams(Object.entries(params).filter(([_, v]) => v !== void 0)) : "";
1013
+ const endpoint = `/accounts${query}`;
1014
+ const response = await this.send("GET", endpoint, {});
1015
+ const encrypted = await response.json();
1016
+ const decrypted = await this.decrypt(encrypted);
1017
+ return throwIfApiError(decrypted);
1018
+ }
1019
+ async activateAccount(accountUuid) {
1020
+ const endpoint = `/accounts/${accountUuid}/activate`;
1021
+ await this.send("POST", endpoint, {});
1022
+ }
1023
+ async deactivateAccount(accountUuid) {
1024
+ const endpoint = `/accounts/${accountUuid}/deactivate`;
1025
+ await this.send("POST", endpoint, {});
1026
+ }
1027
+ async manageOnboarding(accountUuid, action) {
1028
+ const endpoint = `/accounts/${accountUuid}/onboarding`;
1029
+ await this.send("POST", endpoint, { action });
1030
+ }
1031
+ async createAddress(accountUuid, data) {
1032
+ const endpoint = `/accounts/${accountUuid}/addresses`;
1033
+ const response = await this.send("POST", endpoint, data);
1034
+ const encrypted = await response.json();
1035
+ const decrypted = await this.decrypt(encrypted);
1036
+ return throwIfApiError(decrypted);
1037
+ }
1038
+ async getAddresses(accountUuid, params) {
1039
+ const query = params ? "?" + new URLSearchParams(Object.entries(params).filter(([_, v]) => v !== void 0)) : "";
1040
+ const endpoint = `/accounts/${accountUuid}/addresses${query}`;
1041
+ const response = await this.send("GET", endpoint, {});
1042
+ const encrypted = await response.json();
1043
+ const decrypted = await this.decrypt(encrypted);
1044
+ return throwIfApiError(decrypted);
1045
+ }
1046
+ async updateAddress(accountUuid, addressUuid, data) {
1047
+ const endpoint = `/accounts/${accountUuid}/addresses/${addressUuid}`;
1048
+ const response = await this.send("PUT", endpoint, data);
1049
+ const encrypted = await response.json();
1050
+ const decrypted = await this.decrypt(encrypted);
1051
+ return throwIfApiError(decrypted);
1052
+ }
1053
+ async deleteAddress(accountUuid, addressUuid) {
1054
+ const endpoint = `/accounts/${accountUuid}/addresses/${addressUuid}`;
1055
+ await this.send("DELETE", endpoint, {});
1056
+ }
1057
+ async createDossier(accountUuid, data) {
1058
+ const endpoint = `/accounts/${accountUuid}/dossiers`;
1059
+ const response = await this.send("POST", endpoint, data);
1060
+ const encrypted = await response.json();
1061
+ const decrypted = await this.decrypt(encrypted);
1062
+ return throwIfApiError(decrypted);
1063
+ }
1064
+ async getDossiers(accountUuid, params) {
1065
+ const query = params ? "?" + new URLSearchParams(Object.entries(params).filter(([_, v]) => v !== void 0)) : "";
1066
+ const endpoint = `/accounts/${accountUuid}/dossiers${query}`;
1067
+ const response = await this.send("GET", endpoint, {});
1068
+ const encrypted = await response.json();
1069
+ const decrypted = await this.decrypt(encrypted);
1070
+ return throwIfApiError(decrypted);
1071
+ }
1072
+ async getDossier(accountUuid, dossierUuid) {
1073
+ const endpoint = `/accounts/${accountUuid}/dossiers/${dossierUuid}`;
1074
+ const response = await this.send("GET", endpoint, {});
1075
+ const encrypted = await response.json();
1076
+ const decrypted = await this.decrypt(encrypted);
1077
+ return throwIfApiError(decrypted);
1078
+ }
1079
+ async updateDossier(accountUuid, dossierUuid, data) {
1080
+ const endpoint = `/accounts/${accountUuid}/dossiers/${dossierUuid}`;
1081
+ const response = await this.send("PUT", endpoint, data);
1082
+ const encrypted = await response.json();
1083
+ const decrypted = await this.decrypt(encrypted);
1084
+ return throwIfApiError(decrypted);
1085
+ }
1086
+ async replaceDossier(accountUuid, dossierUuid, data) {
1087
+ const endpoint = `/accounts/${accountUuid}/dossiers/${dossierUuid}`;
1088
+ const response = await this.send("PATCH", endpoint, data);
1089
+ const encrypted = await response.json();
1090
+ const decrypted = await this.decrypt(encrypted);
1091
+ return throwIfApiError(decrypted);
1092
+ }
1093
+ async deleteDossier(accountUuid, dossierUuid) {
1094
+ const endpoint = `/accounts/${accountUuid}/dossiers/${dossierUuid}`;
1095
+ await this.send("DELETE", endpoint, {});
1096
+ }
1097
+ }
1098
+ class AuthGateway extends AlcoreBase {
1099
+ constructor(jwt, cryptor, logger) {
1100
+ super(jwt, cryptor, logger);
1101
+ this.logger.debug(`🔐 AuthGateway initialized`);
1102
+ }
1103
+ /**
1104
+ * Generate scoped JWT for specific account (JWT downgrade)
1105
+ * Exchanges business-level JWT for consumer-level JWT
1106
+ * Uses AlcoreBase.send() to follow the same pattern as all other gateways:
1107
+ * - Endpoint passed in encrypted payload
1108
+ * - Request sent to /alcore (not /alcore/v3/auth)
1109
+ * - Middleware handles routing
1110
+ *
1111
+ * @param data - Request containing account_uuid to scope to
1112
+ * @returns New scoped JWT token
1113
+ */
1114
+ async generateScopedToken(data) {
1115
+ this.logger.debug("🔐 AuthGateway: Generating scoped token");
1116
+ this.logger.debug("🌐 Endpoint: /v3/auth");
1117
+ this.logger.debug("🌐 Account UUID: " + data.account_uuid);
1118
+ const response = await this.send("POST", "/v3/auth", data);
1119
+ const decryptedResponse = await this.decrypt(await response.json());
1120
+ this.logger.debug("✅ Scoped token generated successfully");
1121
+ return decryptedResponse;
1122
+ }
1123
+ }
1124
+ class WalletsApiService {
1125
+ constructor(gateway) {
1126
+ this.gateway = gateway;
1127
+ }
1128
+ async listWallets(accountUuid, params) {
1129
+ return this.gateway.listWallets(accountUuid, params);
1130
+ }
1131
+ async loadFunds(walletUuid, params) {
1132
+ return this.gateway.loadFunds(walletUuid, params);
1133
+ }
1134
+ }
1135
+ class PaymentInstrumentsApiService {
1136
+ constructor(gateway) {
1137
+ this.gateway = gateway;
1138
+ }
1139
+ async createPaymentInstrument(data) {
1140
+ return this.gateway.createPaymentInstrument(data);
1141
+ }
1142
+ async getPaymentInstrument(paymentInstrumentUuid) {
1143
+ return this.gateway.getPaymentInstrument(paymentInstrumentUuid);
1144
+ }
1145
+ async deletePaymentInstrument(paymentInstrumentUuid) {
1146
+ return this.gateway.deletePaymentInstrument(paymentInstrumentUuid);
1147
+ }
1148
+ async debitFunds(data) {
1149
+ return this.gateway.debitFunds(data);
1150
+ }
1151
+ async listCards(accountUuid, params) {
1152
+ return this.gateway.listCards(accountUuid, params);
1153
+ }
1154
+ }
1155
+ class AccountsApiService {
1156
+ constructor(gateway) {
1157
+ this.gateway = gateway;
1158
+ }
1159
+ async createAccount(data) {
1160
+ return this.gateway.createAccount(data);
1161
+ }
1162
+ async getAccount(accountUuid) {
1163
+ return this.gateway.getAccount(accountUuid);
1164
+ }
1165
+ async updateAccount(accountUuid, data) {
1166
+ return this.gateway.updateAccount(accountUuid, data);
1167
+ }
1168
+ async deleteAccount(accountUuid) {
1169
+ return this.gateway.deleteAccount(accountUuid);
1170
+ }
1171
+ async listAccounts(params) {
1172
+ return this.gateway.listAccounts(params);
1173
+ }
1174
+ async activateAccount(accountUuid) {
1175
+ return this.gateway.activateAccount(accountUuid);
1176
+ }
1177
+ async deactivateAccount(accountUuid) {
1178
+ return this.gateway.deactivateAccount(accountUuid);
1179
+ }
1180
+ async manageOnboarding(accountUuid, action) {
1181
+ return this.gateway.manageOnboarding(accountUuid, action);
1182
+ }
1183
+ async createAddress(accountUuid, data) {
1184
+ return this.gateway.createAddress(accountUuid, data);
1185
+ }
1186
+ async getAddresses(accountUuid, params) {
1187
+ return this.gateway.getAddresses(accountUuid, params);
1188
+ }
1189
+ async updateAddress(accountUuid, addressUuid, data) {
1190
+ return this.gateway.updateAddress(accountUuid, addressUuid, data);
1191
+ }
1192
+ async deleteAddress(accountUuid, addressUuid) {
1193
+ return this.gateway.deleteAddress(accountUuid, addressUuid);
1194
+ }
1195
+ async createDossier(accountUuid, data) {
1196
+ return this.gateway.createDossier(accountUuid, data);
1197
+ }
1198
+ async getDossiers(accountUuid, params) {
1199
+ return this.gateway.getDossiers(accountUuid, params);
1200
+ }
1201
+ async getDossier(accountUuid, dossierUuid) {
1202
+ return this.gateway.getDossier(accountUuid, dossierUuid);
1203
+ }
1204
+ async updateDossier(accountUuid, dossierUuid, data) {
1205
+ return this.gateway.updateDossier(accountUuid, dossierUuid, data);
1206
+ }
1207
+ async replaceDossier(accountUuid, dossierUuid, data) {
1208
+ return this.gateway.replaceDossier(accountUuid, dossierUuid, data);
1209
+ }
1210
+ async deleteDossier(accountUuid, dossierUuid) {
1211
+ return this.gateway.deleteDossier(accountUuid, dossierUuid);
1212
+ }
1213
+ }
1214
+ class PaymentProcessor {
1215
+ constructor(gateway, logger) {
1216
+ this.gateway = gateway;
1217
+ this.logger = logger;
1218
+ }
1219
+ /**
1220
+ * Process an add card request through the gateway
1221
+ */
1222
+ async processAddCard(accountUuid, request) {
1223
+ this.logger.debug("PaymentProcessor: Starting add card processing");
1224
+ this.logger.debug("PaymentProcessor: Request data: " + JSON.stringify(request, null, 2));
1225
+ try {
1226
+ const result = await this.gateway.add_card(accountUuid, request);
1227
+ this.logger.debug("PaymentProcessor: Add card processing completed successfully");
1228
+ return result;
1229
+ } catch (error) {
1230
+ this.logger.debug("PaymentProcessor: Add card processing failed");
1231
+ this.logger.debug("PaymentProcessor: Error details: " + JSON.stringify(error));
1232
+ throw error;
1233
+ }
1234
+ }
1235
+ /**
1236
+ * Validate that a request has all required fields before processing
1237
+ */
1238
+ validateRequest(request) {
1239
+ const requiredFields = [
1240
+ "external_id",
1241
+ "pan",
1242
+ "exp_year",
1243
+ "exp_month",
1244
+ "postal_code",
1245
+ "security_code"
1246
+ ];
1247
+ for (const field of requiredFields) {
1248
+ if (!request[field]) {
1249
+ throw new Error(`Missing required field: ${field}`);
1250
+ }
1251
+ }
1252
+ this.logger.debug("PaymentProcessor: Request validation passed");
1253
+ }
1254
+ /**
1255
+ * Process payment with pre-validation
1256
+ */
1257
+ async processAddCardWithValidation(accountUuid, request) {
1258
+ this.logger.debug("PaymentProcessor: Starting add card processing with validation");
1259
+ this.validateRequest(request);
1260
+ return await this.processAddCard(accountUuid, request);
1261
+ }
1262
+ /**
1263
+ * Process an add bank account request through the gateway
1264
+ */
1265
+ async processAddBankAccount(accountUuid, request) {
1266
+ this.logger.debug("PaymentProcessor: Starting add bank account processing");
1267
+ this.logger.debug("PaymentProcessor: Request data: " + JSON.stringify(request, null, 2));
1268
+ try {
1269
+ const result = await this.gateway.add_bank_account(accountUuid, request);
1270
+ this.logger.debug("PaymentProcessor: Add bank account processing completed successfully");
1271
+ return result;
1272
+ } catch (error) {
1273
+ this.logger.debug("PaymentProcessor: Add bank account processing failed");
1274
+ this.logger.debug("PaymentProcessor: Error details: " + JSON.stringify(error));
1275
+ throw error;
1276
+ }
1277
+ }
1278
+ /**
1279
+ * Validate that a bank account request has all required fields before processing
1280
+ */
1281
+ validateBankAccountRequest(request) {
1282
+ const requiredFields = [
1283
+ "external_id",
1284
+ "country",
1285
+ "currency",
1286
+ "bank_account_details"
1287
+ ];
1288
+ for (const field of requiredFields) {
1289
+ if (!request[field]) {
1290
+ throw new Error(`Missing required field: ${field}`);
1291
+ }
1292
+ }
1293
+ this.logger.debug("PaymentProcessor: Bank account request validation passed");
1294
+ }
1295
+ /**
1296
+ * Process bank account addition with pre-validation
1297
+ */
1298
+ async processAddBankAccountWithValidation(accountUuid, request) {
1299
+ this.logger.debug("PaymentProcessor: Starting add bank account processing with validation");
1300
+ this.validateBankAccountRequest(request);
1301
+ return await this.processAddBankAccount(accountUuid, request);
1302
+ }
1303
+ async processGetBankAccounts(accountUuid) {
1304
+ this.logger.debug("PaymentProcessor: Starting get bank accounts processing");
1305
+ try {
1306
+ const result = await this.gateway.get_bank_accounts(accountUuid);
1307
+ this.logger.debug("PaymentProcessor: Get bank accounts processing completed successfully");
1308
+ return result;
1309
+ } catch (error) {
1310
+ this.logger.debug("PaymentProcessor: Get bank accounts processing failed");
1311
+ this.logger.debug("PaymentProcessor: Error details: " + JSON.stringify(error));
1312
+ throw error;
1313
+ }
1314
+ }
1315
+ async processDeleteBankAccount(accountUuid, uuid) {
1316
+ this.logger.debug("PaymentProcessor: Starting delete bank account processing");
1317
+ try {
1318
+ const result = await this.gateway.delete_bank_account(accountUuid, uuid);
1319
+ this.logger.debug("PaymentProcessor: Delete bank account processing completed successfully");
1320
+ return result;
1321
+ } catch (error) {
1322
+ this.logger.debug("PaymentProcessor: Delete bank account processing failed");
1323
+ this.logger.debug("PaymentProcessor: Error details: " + JSON.stringify(error));
1324
+ throw error;
1325
+ }
1326
+ }
1327
+ }
1328
+ function NewAddCardRequest(params) {
1329
+ const { external_id, name, pan, expiry, code, zip } = params;
1330
+ const expiryParts = expiry.split("/");
1331
+ const month = expiryParts[0];
1332
+ const year = expiryParts[1];
1333
+ let data = {
1334
+ external_id,
1335
+ pan,
1336
+ exp_year: year,
1337
+ exp_month: month,
1338
+ security_code: code,
1339
+ postal_code: zip,
1340
+ name_on_card: name
1341
+ };
1342
+ data = getSanitizedBody(data);
1343
+ return data;
1344
+ }
1345
+ function NewPaymentInstrumentRequest(accountUuid, paymentInstrumentType, cardDetails, externalId, metadata) {
1346
+ return {
1347
+ account_uuid: accountUuid,
1348
+ external_id: externalId,
1349
+ payment_instrument_type: paymentInstrumentType,
1350
+ payment_instrument_details: {
1351
+ card: cardDetails
1352
+ },
1353
+ metadata
1354
+ };
1355
+ }
1356
+ function NewCardInstrumentFromForm(pan, expiry, securityCode, nameOnCard, addressLine1, city, state, postal_code, country, addressLine2, phoneNumber, emailAddress) {
1357
+ const expiryParts = expiry.split("/");
1358
+ const exp_month = expiryParts[0];
1359
+ const exp_year = expiryParts[1];
1360
+ return {
1361
+ pan: pan.replace(/\s/g, ""),
1362
+ // Remove spaces
1363
+ exp_month,
1364
+ exp_year,
1365
+ security_code: securityCode,
1366
+ name_on_card: nameOnCard,
1367
+ phone_number: phoneNumber,
1368
+ email_address: emailAddress,
1369
+ billing_address: {
1370
+ line_1: addressLine1,
1371
+ line_2: addressLine2,
1372
+ city,
1373
+ state,
1374
+ postal_code,
1375
+ country
1376
+ }
1377
+ };
1378
+ }
1379
+ function NewDebitFundsRequest(walletUuid, externalId, amount, currency, merchantDetails, authType = "AUTHCAP", paymentInstrumentUuid, paymentInstrument, description, threeDSOptions, metadata) {
1380
+ return {
1381
+ wallet_uuid: walletUuid,
1382
+ external_id: externalId,
1383
+ amount,
1384
+ currency,
1385
+ auth_type: authType,
1386
+ payment_instrument_uuid: paymentInstrumentUuid,
1387
+ payment_instrument: paymentInstrument,
1388
+ description,
1389
+ merchant_details: merchantDetails,
1390
+ "3ds_options": threeDSOptions,
1391
+ metadata
1392
+ };
1393
+ }
1394
+ function createDefaultMerchantDetails() {
1395
+ return {
1396
+ name: "Demo Merchant Store",
1397
+ merchant_id: "DEMO_MERCHANT_001"
1398
+ };
1399
+ }
1400
+ function NewAddBankAccountRequest(params) {
1401
+ const { external_id, country, currency, bank_account_details, metadata } = params;
1402
+ let data = {
1403
+ external_id,
1404
+ country,
1405
+ currency,
1406
+ bank_account_details,
1407
+ metadata
1408
+ };
1409
+ data = getSanitizedBody(data);
1410
+ return data;
1411
+ }
1412
+ function NewLoadFundsRequest(params) {
1413
+ const data = {
1414
+ payment_method_uuid: params.payment_method_uuid,
1415
+ amount: params.amount,
1416
+ external_id: params.external_id,
1417
+ service_fees: params.service_fees,
1418
+ transaction_options: params.transaction_options,
1419
+ metadata: params.metadata
1420
+ };
1421
+ return getSanitizedBody(data);
1422
+ }
1423
+ function NewWithdrawFundsRequest(params) {
1424
+ const data = {
1425
+ payment_method_uuid: params.payment_method_uuid,
1426
+ amount: params.amount,
1427
+ external_id: params.external_id,
1428
+ service_fees: params.service_fees,
1429
+ transaction_options: params.transaction_options,
1430
+ metadata: params.metadata
1431
+ };
1432
+ return getSanitizedBody(data);
1433
+ }
1434
+ function NewSendFundsRequest(params) {
1435
+ const data = {
1436
+ destination_wallet_uuid: params.destination_wallet_uuid,
1437
+ external_id: params.external_id,
1438
+ amount: params.amount,
1439
+ service_fees: params.service_fees,
1440
+ description: params.description,
1441
+ metadata: params.metadata
1442
+ };
1443
+ return getSanitizedBody(data);
1444
+ }
1445
+ function NewTransferFundsRequest(params) {
1446
+ const data = {
1447
+ beneficiary_uuid: params.beneficiary_uuid,
1448
+ payout_method_uuid: params.payout_method_uuid,
1449
+ amount: params.amount,
1450
+ service_fees: params.service_fees,
1451
+ description: params.description,
1452
+ external_id: params.external_id,
1453
+ metadata: params.metadata
1454
+ };
1455
+ return getSanitizedBody(data);
1456
+ }
1457
+ function NewCreditFundsRequest(params) {
1458
+ const data = {
1459
+ amount: params.amount,
1460
+ currency: params.currency,
1461
+ external_id: params.external_id,
1462
+ vault_name: params.vault_name,
1463
+ metadata: params.metadata
1464
+ };
1465
+ return getSanitizedBody(data);
1466
+ }
1467
+ function NewPromoFundsRequest(params) {
1468
+ const data = {
1469
+ amount: params.amount,
1470
+ external_id: params.external_id,
1471
+ description: params.description,
1472
+ metadata: params.metadata
1473
+ };
1474
+ return getSanitizedBody(data);
1475
+ }
1476
+ function NewAccountRequest(params) {
1477
+ const data = {
1478
+ external_id: params.external_id,
1479
+ account_type: params.account_type,
1480
+ profile: params.profile,
1481
+ information: params.information,
1482
+ primary_address: params.primary_address,
1483
+ business_account_uuid: params.business_account_uuid,
1484
+ parent_account_uuid: params.parent_account_uuid,
1485
+ metadata: params.metadata
1486
+ };
1487
+ return getSanitizedBody(data);
1488
+ }
1489
+ function NewAddressRequest(params) {
1490
+ const data = {
1491
+ label: params.label,
1492
+ line_1: params.line_1,
1493
+ line_2: params.line_2,
1494
+ city: params.city,
1495
+ state: params.state,
1496
+ postal_code: params.postal_code,
1497
+ country: params.country,
1498
+ primary: params.primary,
1499
+ external_id: params.external_id
1500
+ };
1501
+ return getSanitizedBody(data);
1502
+ }
1503
+ function NewGenerateMobileTokenRequest(params) {
1504
+ const data = {
1505
+ account_uuid: params.account_uuid,
1506
+ with_plaid_sdk_token: params.with_plaid_sdk_token
1507
+ };
1508
+ return getSanitizedBody(data);
1509
+ }
1510
+ function NewGeneratePlaidTokenRequest(params) {
1511
+ const data = {
1512
+ account_uuid: params.account_uuid,
1513
+ platform: params.platform,
1514
+ payment_method_uuid: params.payment_method_uuid
1515
+ };
1516
+ return getSanitizedBody(data);
1517
+ }
1518
+ function NewGenerateWebSessionRequest(params) {
1519
+ const data = {
1520
+ account_uuid: params.account_uuid
1521
+ };
1522
+ return getSanitizedBody(data);
1523
+ }
1524
+ function NewGeneratePdsTokenRequest(params) {
1525
+ const data = {
1526
+ wallet_uuid: params.wallet_uuid
1527
+ };
1528
+ return getSanitizedBody(data);
1529
+ }
1530
+ function NewGenerateScopedTokenRequest(params) {
1531
+ return {
1532
+ account_uuid: params.account_uuid
1533
+ };
1534
+ }
1535
+ function NewDossierRequest(params) {
1536
+ const data = {
1537
+ external_id: params.external_id,
1538
+ documents: params.documents,
1539
+ metadata: params.metadata
1540
+ };
1541
+ return getSanitizedBody(data);
1542
+ }
1543
+ function NewDossierReplaceRequest(params) {
1544
+ const data = {
1545
+ external_id: params.external_id,
1546
+ documents: params.documents,
1547
+ metadata: params.metadata
1548
+ };
1549
+ return getSanitizedBody(data);
1550
+ }
1551
+ class BaseFieldPlugin {
1552
+ constructor() {
1553
+ this.eventListeners = /* @__PURE__ */ new Map();
1554
+ this.configs = /* @__PURE__ */ new Map();
1555
+ }
1556
+ /**
1557
+ * Default sanitization - remove leading/trailing whitespace
1558
+ */
1559
+ sanitize(value, config) {
1560
+ return value.trim();
1561
+ }
1562
+ /**
1563
+ * Default raw value - just remove formatting spaces
1564
+ */
1565
+ getRawValue(formattedValue, config) {
1566
+ return formattedValue.replace(/\s/g, "");
1567
+ }
1568
+ /**
1569
+ * Mount plugin to DOM element with event listeners
1570
+ */
1571
+ mount(element, config) {
1572
+ const finalConfig = { ...this.getDefaultConfig(), ...config };
1573
+ this.configs.set(element, finalConfig);
1574
+ const listeners = /* @__PURE__ */ new Map();
1575
+ this.eventListeners.set(element, listeners);
1576
+ if (element instanceof HTMLInputElement) {
1577
+ this.setupInputElement(element, finalConfig);
1578
+ }
1579
+ this.onMount?.(element, finalConfig);
1580
+ }
1581
+ /**
1582
+ * Unmount plugin from DOM element
1583
+ */
1584
+ unmount(element) {
1585
+ const listeners = this.eventListeners.get(element);
1586
+ if (listeners) {
1587
+ listeners.forEach((listener, event) => {
1588
+ element.removeEventListener(event, listener);
1589
+ });
1590
+ this.eventListeners.delete(element);
1591
+ }
1592
+ this.configs.delete(element);
1593
+ this.onUnmount?.(element);
1594
+ }
1595
+ /**
1596
+ * Setup event listeners for input elements
1597
+ */
1598
+ setupInputElement(input, config) {
1599
+ const listeners = this.eventListeners.get(input);
1600
+ if (config.formatOnType) {
1601
+ const inputListener = (e) => {
1602
+ const target = e.target;
1603
+ const result = this.format(target.value, config);
1604
+ if (result.formattedValue !== target.value) {
1605
+ target.value = result.formattedValue;
1606
+ if (result.cursorPosition !== void 0) {
1607
+ target.setSelectionRange(result.cursorPosition, result.cursorPosition);
1608
+ }
1609
+ }
1610
+ };
1611
+ input.addEventListener("input", inputListener);
1612
+ listeners.set("input", inputListener);
1613
+ }
1614
+ if (config.validateOnBlur) {
1615
+ const blurListener = (e) => {
1616
+ const target = e.target;
1617
+ const validation = this.validate(target.value, config);
1618
+ this.displayValidation(target, validation, config);
1619
+ };
1620
+ input.addEventListener("blur", blurListener);
1621
+ listeners.set("blur", blurListener);
1622
+ }
1623
+ if (config.validateOnType) {
1624
+ const validateListener = (e) => {
1625
+ const target = e.target;
1626
+ const validation = this.validate(target.value, config);
1627
+ this.displayValidation(target, validation, config);
1628
+ };
1629
+ input.addEventListener("input", validateListener);
1630
+ listeners.set("input-validate", validateListener);
1631
+ }
1632
+ if (config.placeholder) input.placeholder = config.placeholder;
1633
+ if (config.maxLength) input.maxLength = config.maxLength;
1634
+ if (config.ariaLabel) input.setAttribute("aria-label", config.ariaLabel);
1635
+ if (config.ariaDescribedBy) input.setAttribute("aria-describedby", config.ariaDescribedBy);
1636
+ }
1637
+ /**
1638
+ * Display validation results on the element
1639
+ */
1640
+ displayValidation(element, result, config) {
1641
+ if (!config.showErrorsInline) return;
1642
+ if (config.errorClassName) element.classList.remove(config.errorClassName);
1643
+ if (config.successClassName) element.classList.remove(config.successClassName);
1644
+ if (result.isValid && config.successClassName) {
1645
+ element.classList.add(config.successClassName);
1646
+ } else if (!result.isValid && config.errorClassName) {
1647
+ element.classList.add(config.errorClassName);
1648
+ }
1649
+ this.updateErrorMessage(element, result.error);
1650
+ }
1651
+ /**
1652
+ * Update error message display
1653
+ */
1654
+ updateErrorMessage(element, error) {
1655
+ let errorElement = element.parentElement?.querySelector(".alviere-field-error");
1656
+ if (error) {
1657
+ if (!errorElement) {
1658
+ errorElement = document.createElement("div");
1659
+ errorElement.className = "alviere-field-error";
1660
+ element.parentElement?.appendChild(errorElement);
1661
+ }
1662
+ errorElement.textContent = error;
1663
+ errorElement.style.display = "block";
1664
+ } else if (errorElement) {
1665
+ errorElement.style.display = "none";
1666
+ }
1667
+ }
1668
+ /**
1669
+ * Get default configuration for this plugin
1670
+ */
1671
+ getDefaultConfig() {
1672
+ return {
1673
+ validateOnBlur: true,
1674
+ formatOnType: true,
1675
+ showErrorsInline: true,
1676
+ errorClassName: "alviere-field-error",
1677
+ successClassName: "alviere-field-success"
1678
+ };
1679
+ }
1680
+ }
1681
+ const CARD_TYPES = {
1682
+ visa: {
1683
+ name: "Visa",
1684
+ pattern: /^4/,
1685
+ gaps: [4, 8, 12],
1686
+ lengths: [13, 16, 19],
1687
+ code: { name: "CVV", size: 3 }
1688
+ },
1689
+ mastercard: {
1690
+ name: "Mastercard",
1691
+ pattern: /^(5[1-5][0-9]{2}|222[1-9]|22[3-9][0-9]|2[3-6][0-9]{2}|27[01][0-9]|2720)/,
1692
+ gaps: [4, 8, 12],
1693
+ lengths: [16],
1694
+ code: { name: "CVC", size: 3 }
1695
+ },
1696
+ amex: {
1697
+ name: "American Express",
1698
+ pattern: /^3[47]/,
1699
+ gaps: [4, 10],
1700
+ lengths: [15],
1701
+ code: { name: "CID", size: 4 }
1702
+ },
1703
+ diners: {
1704
+ name: "Diners Club",
1705
+ pattern: /^3[0689]/,
1706
+ gaps: [4, 10],
1707
+ lengths: [14],
1708
+ code: { name: "CVV", size: 3 }
1709
+ },
1710
+ discover: {
1711
+ name: "Discover",
1712
+ pattern: /^6([045]|22)/,
1713
+ gaps: [4, 8, 12],
1714
+ lengths: [16, 19],
1715
+ code: { name: "CID", size: 3 }
1716
+ },
1717
+ jcb: {
1718
+ name: "JCB",
1719
+ pattern: /^35/,
1720
+ gaps: [4, 8, 12],
1721
+ lengths: [16],
1722
+ code: { name: "CVV", size: 3 }
1723
+ }
1724
+ };
1725
+ class CardNumberPlugin extends BaseFieldPlugin {
1726
+ constructor() {
1727
+ super(...arguments);
1728
+ this.name = "card-number";
1729
+ this.version = "1.0.0";
1730
+ this.description = "Credit card number formatting and validation";
1731
+ this.currentCardType = null;
1732
+ }
1733
+ /**
1734
+ * Validate card number using Luhn algorithm and card type patterns
1735
+ */
1736
+ validate(value, config) {
1737
+ const sanitized = this.sanitize(value);
1738
+ if (!sanitized) {
1739
+ return { isValid: false, error: "Card number is required" };
1740
+ }
1741
+ if (!/^\d+$/.test(sanitized)) {
1742
+ return { isValid: false, error: "Card number must contain only digits" };
1743
+ }
1744
+ const cardType = this.detectCardType(sanitized);
1745
+ this.currentCardType = cardType;
1746
+ if (!cardType) {
1747
+ return { isValid: false, error: "Invalid card number format" };
1748
+ }
1749
+ if (!cardType.lengths.includes(sanitized.length)) {
1750
+ const expectedLengths = cardType.lengths.join(" or ");
1751
+ return {
1752
+ isValid: false,
1753
+ error: `${cardType.name} card numbers must be ${expectedLengths} digits long`
1754
+ };
1755
+ }
1756
+ if (!this.luhnCheck(sanitized)) {
1757
+ return { isValid: false, error: "Invalid card number" };
1758
+ }
1759
+ if (config?.customValidation) {
1760
+ const customError = config.customValidation(value);
1761
+ if (customError) {
1762
+ return { isValid: false, error: customError };
1763
+ }
1764
+ }
1765
+ return {
1766
+ isValid: true,
1767
+ suggestions: [`${cardType.name} ending in ${sanitized.slice(-4)}`]
1768
+ };
1769
+ }
1770
+ /**
1771
+ * Format card number with appropriate spacing based on card type
1772
+ */
1773
+ format(value, config) {
1774
+ const sanitized = this.sanitize(value);
1775
+ const cardType = this.detectCardType(sanitized) || CARD_TYPES.visa;
1776
+ let formatted = "";
1777
+ let spacesAdded = 0;
1778
+ for (let i = 0; i < sanitized.length; i++) {
1779
+ if (cardType.gaps.includes(i)) {
1780
+ formatted += " ";
1781
+ spacesAdded++;
1782
+ }
1783
+ formatted += sanitized[i];
1784
+ }
1785
+ const cursorPosition = sanitized.length + spacesAdded;
1786
+ return {
1787
+ formattedValue: formatted,
1788
+ cursorPosition
1789
+ };
1790
+ }
1791
+ /**
1792
+ * Remove all non-digit characters
1793
+ */
1794
+ sanitize(value, config) {
1795
+ return value.replace(/\D/g, "");
1796
+ }
1797
+ /**
1798
+ * Get raw value without formatting spaces
1799
+ */
1800
+ getRawValue(formattedValue, config) {
1801
+ return this.sanitize(formattedValue);
1802
+ }
1803
+ /**
1804
+ * Check if this plugin can handle the field type
1805
+ */
1806
+ canHandle(fieldType) {
1807
+ return ["card-number", "cardNumber", "pan", "credit-card"].includes(fieldType);
1808
+ }
1809
+ /**
1810
+ * Get plugin-specific default configuration
1811
+ */
1812
+ getDefaultConfig() {
1813
+ return {
1814
+ ...super.getDefaultConfig(),
1815
+ validateOnType: true,
1816
+ formatOnType: true,
1817
+ placeholder: "1234 5678 9012 3456",
1818
+ maxLength: 23,
1819
+ // Max formatted length for 19-digit cards with spaces
1820
+ ariaLabel: "Credit card number"
1821
+ };
1822
+ }
1823
+ /**
1824
+ * Detect card type based on number pattern
1825
+ */
1826
+ detectCardType(cardNumber) {
1827
+ for (const [key, cardType] of Object.entries(CARD_TYPES)) {
1828
+ if (cardType.pattern.test(cardNumber)) {
1829
+ return cardType;
1830
+ }
1831
+ }
1832
+ return null;
1833
+ }
1834
+ /**
1835
+ * Get the detected card type
1836
+ */
1837
+ getCardType() {
1838
+ return this.currentCardType;
1839
+ }
1840
+ /**
1841
+ * Validate card number using Luhn algorithm
1842
+ */
1843
+ luhnCheck(cardNumber) {
1844
+ let sum = 0;
1845
+ let isEven = false;
1846
+ for (let i = cardNumber.length - 1; i >= 0; i--) {
1847
+ let digit = parseInt(cardNumber.charAt(i), 10);
1848
+ if (isEven) {
1849
+ digit *= 2;
1850
+ if (digit > 9) {
1851
+ digit -= 9;
1852
+ }
1853
+ }
1854
+ sum += digit;
1855
+ isEven = !isEven;
1856
+ }
1857
+ return sum % 10 === 0;
1858
+ }
1859
+ /**
1860
+ * Enhanced mount with card type detection
1861
+ */
1862
+ onMount(element, config) {
1863
+ if (element instanceof HTMLInputElement) {
1864
+ const cardTypeListener = (e) => {
1865
+ const target = e.target;
1866
+ const sanitized = this.sanitize(target.value);
1867
+ const cardType = this.detectCardType(sanitized);
1868
+ if (cardType !== this.currentCardType) {
1869
+ this.currentCardType = cardType;
1870
+ element.dispatchEvent(new CustomEvent("cardTypeChange", {
1871
+ detail: { cardType, element },
1872
+ bubbles: true
1873
+ // Allow event to bubble up to document
1874
+ }));
1875
+ }
1876
+ if (cardType) {
1877
+ const maxFormattedLength = Math.max(...cardType.lengths) + cardType.gaps.length;
1878
+ target.maxLength = maxFormattedLength;
1879
+ }
1880
+ };
1881
+ element.addEventListener("input", cardTypeListener);
1882
+ const listeners = this.eventListeners.get(element);
1883
+ if (listeners) {
1884
+ listeners.set("cardTypeDetection", cardTypeListener);
1885
+ }
1886
+ }
1887
+ }
1888
+ }
1889
+ class FieldPluginRegistry {
1890
+ constructor(config = {}) {
1891
+ this.plugins = /* @__PURE__ */ new Map();
1892
+ this.fieldTypeCache = /* @__PURE__ */ new Map();
1893
+ this.config = {
1894
+ autoRegisterBuiltins: true,
1895
+ enablePluginValidation: true,
1896
+ ...config
1897
+ };
1898
+ this.logger = config.logger;
1899
+ if (this.config.autoRegisterBuiltins) {
1900
+ this.registerBuiltinPlugins();
1901
+ }
1902
+ this.logger?.debug("🔐 FieldPluginRegistry initialized");
1903
+ }
1904
+ /**
1905
+ * Register a field plugin
1906
+ */
1907
+ register(plugin) {
1908
+ if (this.config.enablePluginValidation) {
1909
+ this.validatePlugin(plugin);
1910
+ }
1911
+ this.plugins.set(plugin.name, plugin);
1912
+ this.fieldTypeCache.clear();
1913
+ this.logger?.debug(`FieldPluginRegistry: Registered plugin '${plugin.name}' v${plugin.version}`);
1914
+ }
1915
+ /**
1916
+ * Unregister a field plugin
1917
+ */
1918
+ unregister(pluginName) {
1919
+ const removed = this.plugins.delete(pluginName);
1920
+ if (removed) {
1921
+ this.fieldTypeCache.clear();
1922
+ this.logger?.debug(`FieldPluginRegistry: Unregistered plugin '${pluginName}'`);
1923
+ }
1924
+ return removed;
1925
+ }
1926
+ /**
1927
+ * Get a plugin by name
1928
+ */
1929
+ getPlugin(pluginName) {
1930
+ return this.plugins.get(pluginName);
1931
+ }
1932
+ /**
1933
+ * Get plugin for a specific field type (with caching)
1934
+ */
1935
+ getPluginForFieldType(fieldType) {
1936
+ if (this.fieldTypeCache.has(fieldType)) {
1937
+ return this.fieldTypeCache.get(fieldType);
1938
+ }
1939
+ for (const plugin of this.plugins.values()) {
1940
+ if (plugin.canHandle(fieldType)) {
1941
+ this.fieldTypeCache.set(fieldType, plugin);
1942
+ return plugin;
1943
+ }
1944
+ }
1945
+ const textPlugin = this.plugins.get("text");
1946
+ if (textPlugin) {
1947
+ this.fieldTypeCache.set(fieldType, textPlugin);
1948
+ return textPlugin;
1949
+ }
1950
+ return void 0;
1951
+ }
1952
+ /**
1953
+ * Get all registered plugins
1954
+ */
1955
+ getAllPlugins() {
1956
+ return Array.from(this.plugins.values());
1957
+ }
1958
+ /**
1959
+ * Get plugin names
1960
+ */
1961
+ getPluginNames() {
1962
+ return Array.from(this.plugins.keys());
1963
+ }
1964
+ /**
1965
+ * Check if a plugin is registered
1966
+ */
1967
+ hasPlugin(pluginName) {
1968
+ return this.plugins.has(pluginName);
1969
+ }
1970
+ /**
1971
+ * Get supported field types across all plugins
1972
+ */
1973
+ getSupportedFieldTypes() {
1974
+ const fieldTypes = /* @__PURE__ */ new Set();
1975
+ const commonFieldTypes = [
1976
+ "card-number",
1977
+ "cardNumber",
1978
+ "pan",
1979
+ "expiry",
1980
+ "expiry-date",
1981
+ "expiryDate",
1982
+ "cvv",
1983
+ "cvc",
1984
+ "code",
1985
+ "zip",
1986
+ "zip-code",
1987
+ "postal-code",
1988
+ "text",
1989
+ "name",
1990
+ "cardholder-name"
1991
+ ];
1992
+ for (const fieldType of commonFieldTypes) {
1993
+ if (this.getPluginForFieldType(fieldType)) {
1994
+ fieldTypes.add(fieldType);
1995
+ }
1996
+ }
1997
+ return Array.from(fieldTypes);
1998
+ }
1999
+ /**
2000
+ * Create and mount a plugin for an element
2001
+ */
2002
+ mountPlugin(element, fieldType, config) {
2003
+ const plugin = this.getPluginForFieldType(fieldType);
2004
+ if (!plugin) {
2005
+ this.logger?.warn(`FieldPluginRegistry: No plugin found for field type '${fieldType}'`);
2006
+ return null;
2007
+ }
2008
+ try {
2009
+ plugin.mount(element, config);
2010
+ this.logger?.debug(`FieldPluginRegistry: Mounted '${plugin.name}' plugin on element for field type '${fieldType}'`);
2011
+ return plugin;
2012
+ } catch (error) {
2013
+ this.logger?.error(`FieldPluginRegistry: Failed to mount plugin '${plugin.name}': ${error instanceof Error ? error.message : String(error)}`);
2014
+ return null;
2015
+ }
2016
+ }
2017
+ /**
2018
+ * Unmount plugin from an element
2019
+ */
2020
+ unmountPlugin(element, fieldType) {
2021
+ const plugin = this.getPluginForFieldType(fieldType);
2022
+ if (!plugin) {
2023
+ return false;
2024
+ }
2025
+ try {
2026
+ plugin.unmount(element);
2027
+ this.logger?.debug(`FieldPluginRegistry: Unmounted '${plugin.name}' plugin from element`);
2028
+ return true;
2029
+ } catch (error) {
2030
+ this.logger?.error(`FieldPluginRegistry: Failed to unmount plugin '${plugin.name}': ${error instanceof Error ? error.message : String(error)}`);
2031
+ return false;
2032
+ }
2033
+ }
2034
+ /**
2035
+ * Get plugin registry statistics
2036
+ */
2037
+ getStats() {
2038
+ return {
2039
+ totalPlugins: this.plugins.size,
2040
+ pluginNames: this.getPluginNames(),
2041
+ supportedFieldTypes: this.getSupportedFieldTypes(),
2042
+ cacheSize: this.fieldTypeCache.size
2043
+ };
2044
+ }
2045
+ /**
2046
+ * Clear all caches
2047
+ */
2048
+ clearCaches() {
2049
+ this.fieldTypeCache.clear();
2050
+ }
2051
+ /**
2052
+ * Register all built-in plugins
2053
+ *
2054
+ * Note: ALL plugins are currently disabled as they have no active consumers.
2055
+ * - ui-svelte implements its own card handling in CardPanInput.svelte
2056
+ * - CardNumberPlugin was only used in its own tests
2057
+ * - Other plugins (ExpiryDatePlugin, CVVPlugin, TextPlugin, ZipCodePlugin) were never activated
2058
+ *
2059
+ * The plugin system remains as a future architecture option if needed.
2060
+ *
2061
+ * To re-enable plugins in the future:
2062
+ * 1. Uncomment the imports at the top of this file
2063
+ * 2. Add plugin instances to the builtinPlugins array below
2064
+ * 3. Ensure tests exist for the plugins
2065
+ * 4. Update vitest.config.ts to remove them from coverage exclusions
2066
+ * 5. Update consuming code to actually use the plugins
2067
+ */
2068
+ registerBuiltinPlugins() {
2069
+ const builtinPlugins = [
2070
+ // All plugins disabled - no active consumers
2071
+ // new CardNumberPlugin(),
2072
+ // new ExpiryDatePlugin(),
2073
+ // new CVVPlugin(),
2074
+ // new TextPlugin(),
2075
+ // new ZipCodePlugin()
2076
+ ];
2077
+ for (const plugin of builtinPlugins) {
2078
+ this.register(plugin);
2079
+ }
2080
+ }
2081
+ /**
2082
+ * Validate plugin before registration
2083
+ */
2084
+ validatePlugin(plugin) {
2085
+ if (!plugin.name || typeof plugin.name !== "string") {
2086
+ throw new Error("Plugin must have a valid name");
2087
+ }
2088
+ if (!plugin.version || typeof plugin.version !== "string") {
2089
+ throw new Error("Plugin must have a valid version");
2090
+ }
2091
+ if (typeof plugin.validate !== "function") {
2092
+ throw new Error("Plugin must implement validate method");
2093
+ }
2094
+ if (typeof plugin.format !== "function") {
2095
+ throw new Error("Plugin must implement format method");
2096
+ }
2097
+ if (typeof plugin.sanitize !== "function") {
2098
+ throw new Error("Plugin must implement sanitize method");
2099
+ }
2100
+ if (typeof plugin.canHandle !== "function") {
2101
+ throw new Error("Plugin must implement canHandle method");
2102
+ }
2103
+ if (typeof plugin.mount !== "function") {
2104
+ throw new Error("Plugin must implement mount method");
2105
+ }
2106
+ if (typeof plugin.unmount !== "function") {
2107
+ throw new Error("Plugin must implement unmount method");
2108
+ }
2109
+ if (this.plugins.has(plugin.name)) {
2110
+ this.logger?.warn(`FieldPluginRegistry: Plugin '${plugin.name}' is already registered and will be replaced`);
2111
+ }
2112
+ }
2113
+ }
2114
+ class AlviereCore {
2115
+ constructor(config = {}) {
2116
+ this.authToken = "";
2117
+ this.business_uuid = "";
2118
+ this.account_uuid = "";
2119
+ this.cryptor = null;
2120
+ this.gateways = /* @__PURE__ */ new Map();
2121
+ this.jwt = config.jwt || "";
2122
+ this.debug = config.debug || false;
2123
+ this.publicCertificate = config.publicCertificate || "";
2124
+ this.publicCertificateId = config.publicCertificateId || "";
2125
+ this.business_uuid = config.business_uuid || "";
2126
+ this.logger = new Logger(this.debug);
2127
+ this.logger.debug(`🔐 AlviereCore constructor called with config: ${JSON.stringify(config)}`);
2128
+ if (this.jwt) {
2129
+ const jwtConfig = extractAlviereConfigFromJWT(this.jwt);
2130
+ if (config.jwt) {
2131
+ setRuntimeConfig({
2132
+ ...jwtConfig,
2133
+ certificate: { id: this.publicCertificateId, public_key: this.publicCertificate }
2134
+ });
2135
+ }
2136
+ const extractedAccountUuid = extractAccountUuidFromJWT(this.jwt);
2137
+ if (extractedAccountUuid) {
2138
+ this.account_uuid = extractedAccountUuid;
2139
+ this.logger.debug(`🔐 Extracted account_uuid from JWT sub field: ${this.account_uuid}`);
2140
+ } else {
2141
+ this.logger.debug("⚠️ No account_uuid found in JWT sub field");
2142
+ }
2143
+ this.authToken = this.jwt;
2144
+ this.logger.debug("🔐 Using JWT as auth token for API authentication");
2145
+ }
2146
+ if (config.alviere) {
2147
+ setRuntimeConfig(config.alviere);
2148
+ }
2149
+ }
2150
+ // Update configuration
2151
+ configure(config) {
2152
+ const jwtChanged = config.jwt && config.jwt !== this.jwt;
2153
+ if (config.jwt) {
2154
+ this.jwt = config.jwt;
2155
+ const jwtConfig = extractAlviereConfigFromJWT(config.jwt);
2156
+ if (jwtConfig.domain) {
2157
+ setRuntimeConfig(jwtConfig);
2158
+ }
2159
+ const extractedAccountUuid = extractAccountUuidFromJWT(config.jwt);
2160
+ this.logger.debug(`🔐 Extracted account_uuid from JWT sub field: ${extractedAccountUuid}`);
2161
+ if (extractedAccountUuid) {
2162
+ this.account_uuid = extractedAccountUuid;
2163
+ this.logger.debug(`🔐 Updated account_uuid from JWT sub field: ${this.account_uuid}`);
2164
+ } else {
2165
+ this.logger.debug("⚠️ No account_uuid found in new JWT sub field");
2166
+ }
2167
+ this.authToken = this.jwt;
2168
+ this.logger.debug("🔐 Updated JWT as auth token for API authentication");
2169
+ }
2170
+ if (config.business_uuid !== void 0) {
2171
+ this.business_uuid = config.business_uuid;
2172
+ this.logger.debug(`🔐 Updated business_uuid: ${this.business_uuid}`);
2173
+ }
2174
+ if (typeof config.debug === "boolean" && config.debug !== this.debug) {
2175
+ this.debug = config.debug;
2176
+ this.logger = new Logger(this.debug);
2177
+ this.logger.debug("🔐 Debug mode changed to: " + this.debug);
2178
+ }
2179
+ if (jwtChanged) {
2180
+ this.logger.debug("🔐 JWT changed - clearing gateway cache and cryptor");
2181
+ this.gateways.clear();
2182
+ this.cryptor = null;
2183
+ }
2184
+ if (config.alviere) {
2185
+ setRuntimeConfig(config.alviere);
2186
+ }
2187
+ return this;
2188
+ }
2189
+ /**
2190
+ * Get or create Cryptor instance (lazy initialization with validation)
2191
+ * This ensures we only create Cryptor when it's actually needed and we have a valid RSA key
2192
+ * @throws Error if RSA public key is not available
2193
+ */
2194
+ getOrCreateCryptor() {
2195
+ if (!this.cryptor) {
2196
+ const rsaKey = getRSA_PUB_KEY();
2197
+ if (!rsaKey || rsaKey.trim() === "") {
2198
+ throw new Error(
2199
+ '🔐 Cryptor initialization failed: RSA public key not available. Please ensure JWT is configured with a valid RSA key before attempting encryption operations. Call alviereCore.configure({ jwt: "your-jwt-with-rsa-key" }) first.'
2200
+ );
2201
+ }
2202
+ this.logger.debug("🔐 Creating Cryptor instance with RSA key");
2203
+ this.cryptor = new Cryptor(this.logger);
2204
+ }
2205
+ return this.cryptor;
2206
+ }
2207
+ // Create payment gateway (cached and reused)
2208
+ createPaymentsGateway() {
2209
+ if (!this.gateways.has("payments")) {
2210
+ this.gateways.set(
2211
+ "payments",
2212
+ new PaymentsGateway(this.authToken, this.getOrCreateCryptor(), this.logger)
2213
+ );
2214
+ }
2215
+ return this.gateways.get("payments");
2216
+ }
2217
+ // Create payments service (reuses cached gateway and shared logger)
2218
+ createPaymentsService() {
2219
+ const gateway = this.createPaymentsGateway();
2220
+ return new PaymentProcessor(gateway, this.logger);
2221
+ }
2222
+ // Create wallet services (reuses cached gateway)
2223
+ createWalletsService() {
2224
+ if (!this.gateways.has("wallets")) {
2225
+ this.gateways.set(
2226
+ "wallets",
2227
+ new WalletsGateway(this.authToken, this.getOrCreateCryptor(), this.logger)
2228
+ );
2229
+ }
2230
+ return new WalletsApiService(this.gateways.get("wallets"));
2231
+ }
2232
+ // Create payment instruments service (reuses cached gateway)
2233
+ createPaymentInstrumentsService() {
2234
+ if (!this.gateways.has("paymentInstruments")) {
2235
+ this.gateways.set(
2236
+ "paymentInstruments",
2237
+ new PaymentInstrumentsGateway(this.authToken, this.getOrCreateCryptor(), this.logger)
2238
+ );
2239
+ }
2240
+ return new PaymentInstrumentsApiService(this.gateways.get("paymentInstruments"));
2241
+ }
2242
+ // Create accounts service (reuses cached gateway)
2243
+ createAccountsService() {
2244
+ if (!this.gateways.has("accounts")) {
2245
+ this.gateways.set(
2246
+ "accounts",
2247
+ new AccountsGateway(this.authToken, this.getOrCreateCryptor(), this.logger)
2248
+ );
2249
+ }
2250
+ return new AccountsApiService(this.gateways.get("accounts"));
2251
+ }
2252
+ // Create auth gateway (reuses cached gateway)
2253
+ createAuthGateway() {
2254
+ if (!this.gateways.has("auth")) {
2255
+ if (!this.cryptor) {
2256
+ throw new Error("Cryptor not initialized. Cannot create AuthGateway.");
2257
+ }
2258
+ this.gateways.set("auth", new AuthGateway(this.authToken, this.cryptor, this.logger));
2259
+ }
2260
+ return this.gateways.get("auth");
2261
+ }
2262
+ /**
2263
+ * Generate scoped JWT for specific account (JWT downgrade)
2264
+ * Exchanges the current business-level JWT for a consumer-level JWT
2265
+ *
2266
+ * @param accountUuid - The account UUID to scope the JWT to
2267
+ * @param autoUpdate - If true, automatically updates the SDK with the new JWT (default: true)
2268
+ * @returns The new scoped JWT token
2269
+ */
2270
+ async generateScopedToken(accountUuid, autoUpdate = true) {
2271
+ this.logger.debug(`🔐 Generating scoped token for account: ${accountUuid}`);
2272
+ this.logger.debug(`🔐 Auto-update: ${autoUpdate}`);
2273
+ const authGateway = this.createAuthGateway();
2274
+ const response = await authGateway.generateScopedToken({ account_uuid: accountUuid });
2275
+ this.logger.debug("✅ Scoped token generated successfully");
2276
+ if (autoUpdate && response.access_token) {
2277
+ this.logger.debug("🔄 Auto-updating SDK with new scoped token");
2278
+ this.configure({ jwt: response.access_token });
2279
+ }
2280
+ return response.access_token;
2281
+ }
2282
+ // Get shared instances (for advanced usage)
2283
+ getLogger() {
2284
+ return this.logger;
2285
+ }
2286
+ /**
2287
+ * Get Cryptor instance (lazy initialized with validation)
2288
+ * @throws Error if RSA public key is not available
2289
+ */
2290
+ getCryptor() {
2291
+ return this.getOrCreateCryptor();
2292
+ }
2293
+ // Clear gateway cache (useful for testing or manual cache invalidation)
2294
+ clearCache() {
2295
+ this.gateways.clear();
2296
+ }
2297
+ /**
2298
+ * Get the account UUID extracted from JWT's sub field
2299
+ * @returns The account UUID, or empty string if not available
2300
+ */
2301
+ getAccountUuid() {
2302
+ return this.account_uuid;
2303
+ }
2304
+ /**
2305
+ * Get the business UUID from configuration
2306
+ * @returns The business UUID, or empty string if not configured
2307
+ */
2308
+ getBusinessUuid() {
2309
+ return this.business_uuid;
2310
+ }
2311
+ /**
2312
+ * Determine if the user is accessing the SDK for the first time
2313
+ * Returns true if account_uuid matches business_uuid (user authenticated as business)
2314
+ * Returns false if they differ (JWT already scoped to a specific payee/consumer)
2315
+ *
2316
+ * @returns true if first-time user, false otherwise
2317
+ */
2318
+ isFirstTimeUser() {
2319
+ if (!this.account_uuid || !this.business_uuid) {
2320
+ this.logger.debug(
2321
+ "🔐 Cannot determine first-time user status: missing account_uuid or business_uuid"
2322
+ );
2323
+ return false;
2324
+ }
2325
+ const isFirstTime = this.account_uuid === this.business_uuid;
2326
+ this.logger.debug(
2327
+ `🔐 First-time user check: ${isFirstTime} (account: ${this.account_uuid}, business: ${this.business_uuid})`
2328
+ );
2329
+ return isFirstTime;
2330
+ }
2331
+ /**
2332
+ * Determine if the JWT is scoped to a specific payee/consumer
2333
+ * Returns true if account_uuid differs from business_uuid
2334
+ * Returns false if they match or if either is missing
2335
+ *
2336
+ * @returns true if scoped to payee, false otherwise
2337
+ */
2338
+ isScopedToPayee() {
2339
+ if (!this.account_uuid || !this.business_uuid) {
2340
+ return false;
2341
+ }
2342
+ return this.account_uuid !== this.business_uuid;
2343
+ }
2344
+ // Static utility methods
2345
+ static createValidator(debug = false) {
2346
+ const logger = new Logger(debug);
2347
+ return new Validator(logger);
2348
+ }
2349
+ static createLogger(debug = false) {
2350
+ return new Logger(debug);
2351
+ }
2352
+ static createCryptor(logger) {
2353
+ return new Cryptor(logger);
2354
+ }
2355
+ }
2356
+ export {
2357
+ ALVIERE_DOMAIN,
2358
+ AccountsApiService,
2359
+ AccountsGateway,
2360
+ AlcoreApiError,
2361
+ AlcoreErrorCodes,
2362
+ AlcoreErrorMessages,
2363
+ AlviereCore,
2364
+ AuthGateway,
2365
+ BaseFieldPlugin,
2366
+ CERTIFICATE_ID,
2367
+ CardNumberPlugin,
2368
+ CriticalErrorCodes,
2369
+ Cryptor,
2370
+ DEFAULT_CONFIG,
2371
+ FieldPluginRegistry,
2372
+ Logger,
2373
+ NewAccountRequest,
2374
+ NewAddBankAccountRequest,
2375
+ NewAddCardRequest,
2376
+ NewAddressRequest,
2377
+ NewCardInstrumentFromForm,
2378
+ NewCreditFundsRequest,
2379
+ NewDebitFundsRequest,
2380
+ NewDossierReplaceRequest,
2381
+ NewDossierRequest,
2382
+ NewGenerateMobileTokenRequest,
2383
+ NewGeneratePdsTokenRequest,
2384
+ NewGeneratePlaidTokenRequest,
2385
+ NewGenerateScopedTokenRequest,
2386
+ NewGenerateWebSessionRequest,
2387
+ NewLoadFundsRequest,
2388
+ NewPaymentInstrumentRequest,
2389
+ NewPromoFundsRequest,
2390
+ NewSendFundsRequest,
2391
+ NewTransferFundsRequest,
2392
+ NewWithdrawFundsRequest,
2393
+ PaymentInstrumentsApiService,
2394
+ PaymentInstrumentsGateway,
2395
+ PaymentProcessor,
2396
+ PaymentsGateway,
2397
+ RSA_PUB_KEY,
2398
+ Validator,
2399
+ WalletsApiService,
2400
+ WalletsGateway,
2401
+ createDefaultMerchantDetails,
2402
+ decodeJWTPayload,
2403
+ AlviereCore as default,
2404
+ extractAccountUuidFromJWT,
2405
+ extractAlviereConfigFromJWT,
2406
+ getALVIERE_DOMAIN,
2407
+ getCERTIFICATE_ID,
2408
+ getErrorMessage,
2409
+ getJWTExpiration,
2410
+ getRSA_PUB_KEY,
2411
+ getRuntimeConfig,
2412
+ getSanitizedBody,
2413
+ initializeFromEnvironment,
2414
+ isCriticalError,
2415
+ isJWTExpired,
2416
+ setRuntimeConfig,
2417
+ throwIfApiError
2418
+ };
2419
+ //# sourceMappingURL=index.mjs.map