@dynamicore/jumio-sdk 1.0.0 → 1.0.2

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.
@@ -6,86 +6,81 @@ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
6
6
 
7
7
  var axios__default = /*#__PURE__*/_interopDefault(axios);
8
8
 
9
- // src/core/errors.ts
10
- var JumioError = class extends Error {
11
- isJumioError = true;
12
- statusCode;
13
- rawData;
14
- code;
15
- constructor(message, options) {
16
- super(message);
17
- this.name = "JumioError";
18
- this.statusCode = options?.statusCode;
19
- this.rawData = options?.rawData;
20
- this.code = options?.code;
21
- if (options?.cause) {
22
- this.cause = options.cause;
23
- }
24
- }
9
+ var __defProp = Object.defineProperty;
10
+ var __getOwnPropNames = Object.getOwnPropertyNames;
11
+ var __esm = (fn, res) => function __init() {
12
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
25
13
  };
26
- var JumioTimeoutError = class extends JumioError {
27
- constructor(message = "El servicio de verificaci\xF3n de Jumio excedi\xF3 el tiempo l\xEDmite de espera.", rawData) {
28
- super(message, { code: "TIMEOUT", rawData });
29
- this.name = "JumioTimeoutError";
30
- }
31
- };
32
- var JumioNetworkError = class extends JumioError {
33
- constructor(message = "No fue posible comunicarse con los servidores de validaci\xF3n de identidad.", cause) {
34
- super(message, { code: "NETWORK_ERROR", cause });
35
- this.name = "JumioNetworkError";
36
- }
37
- };
38
- var JumioValidationError = class extends JumioError {
39
- constructor(message = "El documento no pudo ser validado o fue rechazado por Jumio.", rawData) {
40
- super(message, { code: "VALIDATION_FAILED", rawData });
41
- this.name = "JumioValidationError";
42
- }
43
- };
44
- var JumioImageProcessingError = class extends JumioError {
45
- constructor(message, cause) {
46
- super(message, { code: "IMAGE_PROCESSING_ERROR", cause });
47
- this.name = "JumioImageProcessingError";
48
- }
49
- };
50
- var JumioPollingTimeoutError = class extends JumioError {
51
- attempts;
52
- constructor(attempts, message = "La validaci\xF3n sigue en proceso. Por favor verifica nuevamente m\xE1s tarde.", rawData) {
53
- super(message, { code: "POLLING_TIMEOUT", rawData });
54
- this.name = "JumioPollingTimeoutError";
55
- this.attempts = attempts;
56
- }
57
- };
58
- var JumioAbortError = class extends JumioError {
59
- constructor(message = "La operaci\xF3n de validaci\xF3n de Jumio fue cancelada.") {
60
- super(message, { code: "ABORTED" });
61
- this.name = "JumioAbortError";
62
- }
14
+ var __export = (target, all) => {
15
+ for (var name in all)
16
+ __defProp(target, name, { get: all[name], enumerable: true });
63
17
  };
18
+
19
+ // src/core/errors.ts
64
20
  function isJumioError(error) {
65
- return error instanceof JumioError || typeof error === "object" && error !== null && "isJumioError" in error && error.isJumioError === true;
21
+ return error instanceof exports.JumioError || typeof error === "object" && error !== null && "isJumioError" in error && error.isJumioError === true;
66
22
  }
23
+ exports.JumioError = void 0; exports.JumioTimeoutError = void 0; exports.JumioNetworkError = void 0; exports.JumioValidationError = void 0; exports.JumioImageProcessingError = void 0; exports.JumioPollingTimeoutError = void 0; exports.JumioAbortError = void 0;
24
+ var init_errors = __esm({
25
+ "src/core/errors.ts"() {
26
+ exports.JumioError = class extends Error {
27
+ isJumioError = true;
28
+ statusCode;
29
+ rawData;
30
+ code;
31
+ constructor(message, options) {
32
+ super(message);
33
+ this.name = "JumioError";
34
+ this.statusCode = options?.statusCode;
35
+ this.rawData = options?.rawData;
36
+ this.code = options?.code;
37
+ if (options?.cause) {
38
+ this.cause = options.cause;
39
+ }
40
+ }
41
+ };
42
+ exports.JumioTimeoutError = class extends exports.JumioError {
43
+ constructor(message = "El servicio de verificaci\xF3n de Jumio excedi\xF3 el tiempo l\xEDmite de espera.", rawData) {
44
+ super(message, { code: "TIMEOUT", rawData });
45
+ this.name = "JumioTimeoutError";
46
+ }
47
+ };
48
+ exports.JumioNetworkError = class extends exports.JumioError {
49
+ constructor(message = "No fue posible comunicarse con los servidores de validaci\xF3n de identidad.", cause) {
50
+ super(message, { code: "NETWORK_ERROR", cause });
51
+ this.name = "JumioNetworkError";
52
+ }
53
+ };
54
+ exports.JumioValidationError = class extends exports.JumioError {
55
+ constructor(message = "El documento no pudo ser validado o fue rechazado por Jumio.", rawData) {
56
+ super(message, { code: "VALIDATION_FAILED", rawData });
57
+ this.name = "JumioValidationError";
58
+ }
59
+ };
60
+ exports.JumioImageProcessingError = class extends exports.JumioError {
61
+ constructor(message, cause) {
62
+ super(message, { code: "IMAGE_PROCESSING_ERROR", cause });
63
+ this.name = "JumioImageProcessingError";
64
+ }
65
+ };
66
+ exports.JumioPollingTimeoutError = class extends exports.JumioError {
67
+ attempts;
68
+ constructor(attempts, message = "La validaci\xF3n sigue en proceso. Por favor verifica nuevamente m\xE1s tarde.", rawData) {
69
+ super(message, { code: "POLLING_TIMEOUT", rawData });
70
+ this.name = "JumioPollingTimeoutError";
71
+ this.attempts = attempts;
72
+ }
73
+ };
74
+ exports.JumioAbortError = class extends exports.JumioError {
75
+ constructor(message = "La operaci\xF3n de validaci\xF3n de Jumio fue cancelada.") {
76
+ super(message, { code: "ABORTED" });
77
+ this.name = "JumioAbortError";
78
+ }
79
+ };
80
+ }
81
+ });
67
82
 
68
83
  // src/core/envelope.ts
69
- var FINAL_JUMIO_STATUSES = [
70
- "PROCESSED",
71
- "APPROVED_VERIFIED",
72
- "REJECTED",
73
- "FAILED",
74
- "ERROR",
75
- "DENIED",
76
- "EXPIRED",
77
- "ABANDONED",
78
- "DONE",
79
- "COMPLETED",
80
- "NOT_READABLE",
81
- "FRAUD",
82
- "UNSUPPORTED_ID_TYPE"
83
- ];
84
- var APPROVED_JUMIO_STATUSES = [
85
- "APPROVED_VERIFIED",
86
- "DONE",
87
- "COMPLETED"
88
- ];
89
84
  function toLowerText(value) {
90
85
  return String(value ?? "").trim().toLowerCase();
91
86
  }
@@ -93,10 +88,13 @@ function toUpperText(value) {
93
88
  return String(value ?? "").trim().toUpperCase();
94
89
  }
95
90
  function extractEnvelopeData(responseData) {
96
- if (responseData && typeof responseData === "object" && "data" in responseData) {
97
- const candidate = responseData.data;
98
- if (candidate !== void 0) {
99
- return candidate;
91
+ if (responseData && typeof responseData === "object") {
92
+ const obj = responseData;
93
+ if ("data" in obj && obj.data !== void 0) {
94
+ return obj.data;
95
+ }
96
+ if ("values" in obj && obj.values !== void 0) {
97
+ return obj.values;
100
98
  }
101
99
  }
102
100
  return responseData;
@@ -148,7 +146,7 @@ function extractJumioMessage(source) {
148
146
  function isFinalJumioStatus(status) {
149
147
  const upperStatus = toUpperText(status);
150
148
  if (!upperStatus) return false;
151
- return FINAL_JUMIO_STATUSES.some((s) => s === upperStatus);
149
+ return exports.FINAL_JUMIO_STATUSES.some((s) => s === upperStatus);
152
150
  }
153
151
  function isApprovedJumioStatus(status) {
154
152
  const upperStatus = toUpperText(status);
@@ -167,12 +165,54 @@ function resolveVerificationValidity(data, fallbackStatus) {
167
165
  }
168
166
  return isApprovedJumioStatus(fallbackStatus);
169
167
  }
168
+ function encodeUrlToBase64UrlSafe(url) {
169
+ try {
170
+ let base64;
171
+ if (typeof Buffer !== "undefined") {
172
+ base64 = Buffer.from(url, "utf-8").toString("base64");
173
+ } else if (typeof TextEncoder !== "undefined") {
174
+ const encoder = new TextEncoder();
175
+ const data = encoder.encode(url);
176
+ base64 = btoa(String.fromCharCode(...new Uint8Array(data)));
177
+ } else {
178
+ base64 = btoa(url);
179
+ }
180
+ return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
181
+ } catch {
182
+ return null;
183
+ }
184
+ }
185
+ exports.FINAL_JUMIO_STATUSES = void 0; exports.APPROVED_JUMIO_STATUSES = void 0;
186
+ var init_envelope = __esm({
187
+ "src/core/envelope.ts"() {
188
+ exports.FINAL_JUMIO_STATUSES = [
189
+ "PROCESSED",
190
+ "APPROVED_VERIFIED",
191
+ "REJECTED",
192
+ "FAILED",
193
+ "ERROR",
194
+ "DENIED",
195
+ "EXPIRED",
196
+ "ABANDONED",
197
+ "DONE",
198
+ "COMPLETED",
199
+ "NOT_READABLE",
200
+ "FRAUD",
201
+ "UNSUPPORTED_ID_TYPE"
202
+ ];
203
+ exports.APPROVED_JUMIO_STATUSES = [
204
+ "APPROVED_VERIFIED",
205
+ "DONE",
206
+ "COMPLETED"
207
+ ];
208
+ }
209
+ });
170
210
 
171
211
  // src/core/retry.ts
172
212
  function delay(ms, signal) {
173
213
  return new Promise((resolve, reject) => {
174
214
  if (signal?.aborted) {
175
- return reject(new JumioAbortError());
215
+ return reject(new exports.JumioAbortError());
176
216
  }
177
217
  const timer = setTimeout(() => {
178
218
  signal?.removeEventListener("abort", abortHandler);
@@ -180,7 +220,7 @@ function delay(ms, signal) {
180
220
  }, ms);
181
221
  const abortHandler = () => {
182
222
  clearTimeout(timer);
183
- reject(new JumioAbortError());
223
+ reject(new exports.JumioAbortError());
184
224
  };
185
225
  signal?.addEventListener("abort", abortHandler, { once: true });
186
226
  });
@@ -214,14 +254,14 @@ async function withRetry(operation, options = {}) {
214
254
  let lastError;
215
255
  for (let attempt = 1; attempt <= maxRetries; attempt += 1) {
216
256
  if (signal?.aborted) {
217
- throw new JumioAbortError();
257
+ throw new exports.JumioAbortError();
218
258
  }
219
259
  try {
220
260
  return await operation(attempt);
221
261
  } catch (error) {
222
262
  lastError = error;
223
263
  if (signal?.aborted) {
224
- throw new JumioAbortError();
264
+ throw new exports.JumioAbortError();
225
265
  }
226
266
  const isLastAttempt = attempt >= maxRetries;
227
267
  const isRetryable = shouldRetry(error);
@@ -238,8 +278,273 @@ async function withRetry(operation, options = {}) {
238
278
  }
239
279
  throw lastError;
240
280
  }
281
+ var init_retry = __esm({
282
+ "src/core/retry.ts"() {
283
+ init_envelope();
284
+ init_errors();
285
+ }
286
+ });
287
+
288
+ // src/core/webflow.ts
289
+ var webflow_exports = {};
290
+ __export(webflow_exports, {
291
+ buildRedirectUrl: () => buildRedirectUrl,
292
+ parseWebflowReturnParams: () => parseWebflowReturnParams,
293
+ pollWebflowStatus: () => pollWebflowStatus,
294
+ resolveWebflowResult: () => resolveWebflowResult,
295
+ startWebflowSession: () => startWebflowSession
296
+ });
297
+ function buildRedirectUrl(returnUrl, proxyUrl) {
298
+ if (!proxyUrl) {
299
+ return returnUrl;
300
+ }
301
+ const encoded = encodeUrlToBase64UrlSafe(returnUrl);
302
+ if (!encoded) {
303
+ throw new exports.JumioValidationError(
304
+ `No fue posible codificar la URL de retorno: "${returnUrl}"`
305
+ );
306
+ }
307
+ const normalizedProxy = proxyUrl.endsWith("/") ? proxyUrl : `${proxyUrl}/`;
308
+ return `${normalizedProxy}${encoded}`;
309
+ }
310
+ function parseWebflowReturnParams(source) {
311
+ let searchString;
312
+ if (!source) {
313
+ if (typeof window !== "undefined" && window.location) {
314
+ searchString = window.location.search;
315
+ } else {
316
+ return { allParams: {} };
317
+ }
318
+ } else if (typeof source === "string") {
319
+ const questionIdx = source.indexOf("?");
320
+ searchString = questionIdx >= 0 ? source.slice(questionIdx) : "";
321
+ } else if (source instanceof URLSearchParams) {
322
+ searchString = `?${source.toString()}`;
323
+ } else {
324
+ const hrefSearch = source.href ? (() => {
325
+ try {
326
+ return new URL(source.href).search;
327
+ } catch {
328
+ return "";
329
+ }
330
+ })() : "";
331
+ searchString = source.search ?? hrefSearch;
332
+ }
333
+ const params = new URLSearchParams(searchString);
334
+ const allParams = {};
335
+ params.forEach((value, key) => {
336
+ allParams[key] = value;
337
+ });
338
+ const accountId = params.get("accountId") ?? void 0;
339
+ let workflowId = params.get("workflowExecutionId") ?? params.get("workflowId") ?? void 0;
340
+ const rawStatus = params.get("status") ?? void 0;
341
+ if (rawStatus && (!accountId || !workflowId)) {
342
+ const statusParts = rawStatus.split("?");
343
+ const nestedSearch = statusParts.length > 1 ? `?${statusParts.slice(1).join("?")}` : "";
344
+ if (nestedSearch && nestedSearch !== "?") {
345
+ const nestedParams = new URLSearchParams(nestedSearch);
346
+ nestedParams.forEach((value, key) => {
347
+ if (!allParams[key]) allParams[key] = value;
348
+ });
349
+ if (!workflowId) {
350
+ workflowId = nestedParams.get("workflowExecutionId") ?? nestedParams.get("workflowId") ?? workflowId;
351
+ }
352
+ }
353
+ }
354
+ return {
355
+ accountId: accountId || void 0,
356
+ workflowId: workflowId || void 0,
357
+ rawStatus,
358
+ allParams
359
+ };
360
+ }
361
+ function resolveWebflowResult(rawData, accountId, workflowId) {
362
+ if (!rawData || typeof rawData !== "object") return null;
363
+ const data = rawData;
364
+ if (data.valid === true) {
365
+ return {
366
+ valid: true,
367
+ status: String(data.workflowStatus ?? data.status ?? "APPROVED_VERIFIED"),
368
+ decision: data.decision,
369
+ extraction: data.extraction,
370
+ accountId,
371
+ workflowId,
372
+ data: rawData
373
+ };
374
+ }
375
+ if (data.valid === false) {
376
+ return {
377
+ valid: false,
378
+ status: String(data.workflowStatus ?? data.status ?? "REJECTED"),
379
+ decision: data.decision,
380
+ accountId,
381
+ workflowId,
382
+ data: rawData,
383
+ errorMessage: extractJumioMessage(rawData) || "El documento fue rechazado durante la verificacion."
384
+ };
385
+ }
386
+ const capData = data;
387
+ const decisionType = capData?.decision?.type;
388
+ const extractionArr = capData?.capabilities?.extraction ?? [];
389
+ const extraction = extractionArr[0];
390
+ const isExtractionEmpty = extraction !== void 0 && Object.keys(extraction).length === 0;
391
+ if (decisionType === "REJECTED") {
392
+ return {
393
+ valid: false,
394
+ status: "REJECTED",
395
+ decision: decisionType,
396
+ accountId,
397
+ workflowId,
398
+ data: rawData,
399
+ errorMessage: extractJumioMessage(rawData) || "El documento fue rechazado por Jumio."
400
+ };
401
+ }
402
+ if (extraction && !isExtractionEmpty) {
403
+ const isApproved = decisionType === "PASSED" || decisionType === "WARNING";
404
+ return {
405
+ valid: isApproved,
406
+ status: isApproved ? decisionType ?? "PASSED" : decisionType ?? "REJECTED",
407
+ decision: decisionType,
408
+ extraction,
409
+ accountId,
410
+ workflowId,
411
+ data: rawData,
412
+ ...!isApproved ? {
413
+ errorMessage: extractJumioMessage(rawData) || "La verificacion no fue aprobada."
414
+ } : {}
415
+ };
416
+ }
417
+ return null;
418
+ }
419
+ async function pollWebflowStatus(http, params, options = {}) {
420
+ const config = http.getConfig();
421
+ const maxAttempts = options.maxAttempts ?? config.maxPollingAttempts ?? 20;
422
+ const intervalMs = options.pollingIntervalMs ?? config.pollingIntervalMs ?? 1e4;
423
+ const signal = options.signal;
424
+ let lastRawData = {};
425
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
426
+ if (signal?.aborted) {
427
+ throw new exports.JumioAbortError();
428
+ }
429
+ const responseData = await withRetry(
430
+ () => http.getVerificationStatus(params.accountId, params.workflowId, {
431
+ signal,
432
+ timeout: config.statusTimeout,
433
+ clientId: params.clientId
434
+ }),
435
+ {
436
+ maxRetries: config.maxRetries ?? 3,
437
+ initialDelayMs: config.retryDelayMs ?? 800,
438
+ signal
439
+ }
440
+ );
441
+ const firstLevel = extractEnvelopeData(responseData);
442
+ const statusData = extractNestedData(firstLevel) ?? {};
443
+ lastRawData = statusData;
444
+ options.onAttempt?.(attempt, maxAttempts, statusData);
445
+ const result = resolveWebflowResult(
446
+ statusData,
447
+ params.accountId,
448
+ params.workflowId
449
+ );
450
+ if (result !== null) {
451
+ return result;
452
+ }
453
+ if (attempt < maxAttempts) {
454
+ await delay(intervalMs, signal);
455
+ }
456
+ }
457
+ const lastMessage = extractJumioMessage(lastRawData) || "La verificacion Jumio sigue en proceso. Intenta nuevamente en unos momentos.";
458
+ throw new exports.JumioPollingTimeoutError(maxAttempts, lastMessage, lastRawData);
459
+ }
460
+ async function startWebflowSession(http, config, input) {
461
+ const {
462
+ clientId,
463
+ successUrl,
464
+ errorUrl,
465
+ useRedirectProxy = false,
466
+ autoRedirect = false,
467
+ openInNewTab = false,
468
+ signal
469
+ } = input;
470
+ if (!clientId?.trim()) {
471
+ throw new exports.JumioValidationError(
472
+ "Se requiere un identificador de cliente valido (clientId)."
473
+ );
474
+ }
475
+ if (!successUrl?.trim()) {
476
+ throw new exports.JumioValidationError("Se requiere la URL de exito (successUrl).");
477
+ }
478
+ if (!errorUrl?.trim()) {
479
+ throw new exports.JumioValidationError("Se requiere la URL de error (errorUrl).");
480
+ }
481
+ if (signal?.aborted) {
482
+ throw new exports.JumioAbortError();
483
+ }
484
+ const proxyUrl = useRedirectProxy ? config.redirectProxyUrl ?? void 0 : void 0;
485
+ const finalSuccessUrl = buildRedirectUrl(successUrl, proxyUrl);
486
+ const finalErrorUrl = buildRedirectUrl(errorUrl, proxyUrl);
487
+ try {
488
+ const responseData = await withRetry(
489
+ () => http.postVerification(
490
+ {
491
+ client: clientId.trim(),
492
+ successUrl: finalSuccessUrl,
493
+ errorUrl: finalErrorUrl
494
+ },
495
+ { signal, timeout: config.requestTimeout }
496
+ ),
497
+ {
498
+ maxRetries: config.maxRetries ?? 3,
499
+ initialDelayMs: config.retryDelayMs ?? 800,
500
+ signal
501
+ }
502
+ );
503
+ const firstLevel = extractEnvelopeData(responseData);
504
+ const payload = extractNestedData(firstLevel) ?? {};
505
+ const href = payload?.href;
506
+ if (!href) {
507
+ throw new exports.JumioError(
508
+ extractJumioMessage(payload) || "El backend no devolvio la URL de verificacion de Jumio (href).",
509
+ { rawData: payload }
510
+ );
511
+ }
512
+ const result = {
513
+ href,
514
+ accountId: payload?.accountId,
515
+ workflowId: payload?.workflowId,
516
+ data: payload
517
+ };
518
+ if (typeof window !== "undefined") {
519
+ if (openInNewTab) {
520
+ const win = window.open(href, "_blank");
521
+ if (!win || win.closed || typeof win.closed === "undefined") {
522
+ window.location.href = href;
523
+ }
524
+ } else if (autoRedirect) {
525
+ window.location.href = href;
526
+ }
527
+ }
528
+ return result;
529
+ } catch (err) {
530
+ throw err;
531
+ }
532
+ }
533
+ var init_webflow = __esm({
534
+ "src/core/webflow.ts"() {
535
+ init_envelope();
536
+ init_errors();
537
+ init_retry();
538
+ }
539
+ });
540
+
541
+ // src/core/index.ts
542
+ init_errors();
543
+ init_envelope();
544
+ init_retry();
241
545
 
242
546
  // src/core/image.ts
547
+ init_errors();
243
548
  function stripDataUrlPrefix(dataUrl) {
244
549
  if (!dataUrl) return "";
245
550
  const commaIndex = dataUrl.indexOf(",");
@@ -277,7 +582,7 @@ function blobToBase64(blob) {
277
582
  blob.arrayBuffer().then((buffer) => {
278
583
  resolve(arrayBufferToBase64(buffer));
279
584
  }).catch(
280
- (err) => reject(new JumioImageProcessingError("No se pudo leer el archivo binario.", err))
585
+ (err) => reject(new exports.JumioImageProcessingError("No se pudo leer el archivo binario.", err))
281
586
  );
282
587
  return;
283
588
  }
@@ -286,7 +591,7 @@ function blobToBase64(blob) {
286
591
  const dataUrl = String(reader.result ?? "");
287
592
  resolve(stripDataUrlPrefix(dataUrl));
288
593
  };
289
- reader.onerror = () => reject(new JumioImageProcessingError("No se pudo convertir la imagen a base64.", reader.error));
594
+ reader.onerror = () => reject(new exports.JumioImageProcessingError("No se pudo convertir la imagen a base64.", reader.error));
290
595
  reader.readAsDataURL(blob);
291
596
  });
292
597
  }
@@ -305,7 +610,7 @@ function arrayBufferToBase64(buffer) {
305
610
  }
306
611
  async function fetchUrlAsBase64(url, signal) {
307
612
  if (signal?.aborted) {
308
- throw new JumioAbortError();
613
+ throw new exports.JumioAbortError();
309
614
  }
310
615
  const trimmed = url.trim();
311
616
  if (trimmed.startsWith("data:")) {
@@ -314,7 +619,7 @@ async function fetchUrlAsBase64(url, signal) {
314
619
  try {
315
620
  const response = await fetch(trimmed, { signal });
316
621
  if (!response.ok) {
317
- throw new JumioImageProcessingError(
622
+ throw new exports.JumioImageProcessingError(
318
623
  `No se pudo descargar la imagen desde la URL remota (HTTP ${response.status}).`
319
624
  );
320
625
  }
@@ -322,12 +627,12 @@ async function fetchUrlAsBase64(url, signal) {
322
627
  return await blobToBase64(blob);
323
628
  } catch (error) {
324
629
  if (signal?.aborted || error instanceof Error && error.name === "AbortError") {
325
- throw new JumioAbortError();
630
+ throw new exports.JumioAbortError();
326
631
  }
327
- if (error instanceof JumioImageProcessingError) {
632
+ if (error instanceof exports.JumioImageProcessingError) {
328
633
  throw error;
329
634
  }
330
- throw new JumioImageProcessingError(
635
+ throw new exports.JumioImageProcessingError(
331
636
  `Error al descargar o procesar la imagen desde la URL: ${url}`,
332
637
  error
333
638
  );
@@ -335,10 +640,10 @@ async function fetchUrlAsBase64(url, signal) {
335
640
  }
336
641
  async function resolveImageSourceToBase64(source, s3Signer, signal) {
337
642
  if (signal?.aborted) {
338
- throw new JumioAbortError();
643
+ throw new exports.JumioAbortError();
339
644
  }
340
645
  if (!source) {
341
- throw new JumioImageProcessingError("No se proporcion\xF3 una imagen v\xE1lida para la verificaci\xF3n.");
646
+ throw new exports.JumioImageProcessingError("No se proporcion\xF3 una imagen v\xE1lida para la verificaci\xF3n.");
342
647
  }
343
648
  if (typeof Blob !== "undefined" && source instanceof Blob) {
344
649
  return blobToBase64(source);
@@ -355,7 +660,7 @@ async function resolveImageSourceToBase64(source, s3Signer, signal) {
355
660
  if (typeof source === "string") {
356
661
  const text = source.trim();
357
662
  if (!text) {
358
- throw new JumioImageProcessingError("La ruta o contenido de la imagen est\xE1 vac\xEDo.");
663
+ throw new exports.JumioImageProcessingError("La ruta o contenido de la imagen est\xE1 vac\xEDo.");
359
664
  }
360
665
  if (text.startsWith("data:")) {
361
666
  return stripDataUrlPrefix(text);
@@ -380,7 +685,7 @@ async function resolveImageSourceToBase64(source, s3Signer, signal) {
380
685
  return await fetchUrlAsBase64(signedUrl, signal);
381
686
  }
382
687
  } catch (err) {
383
- throw new JumioImageProcessingError(
688
+ throw new exports.JumioImageProcessingError(
384
689
  `No se pudo firmar la ruta de almacenamiento S3: ${text}`,
385
690
  err
386
691
  );
@@ -389,12 +694,16 @@ async function resolveImageSourceToBase64(source, s3Signer, signal) {
389
694
  if (isBase64String(text)) {
390
695
  return stripDataUrlPrefix(text);
391
696
  }
392
- throw new JumioImageProcessingError(
697
+ throw new exports.JumioImageProcessingError(
393
698
  `Formato de imagen no reconocido o ruta inv\xE1lida: ${text.slice(0, 50)}...`
394
699
  );
395
700
  }
396
- throw new JumioImageProcessingError("Tipo de dato de imagen no soportado.");
701
+ throw new exports.JumioImageProcessingError("Tipo de dato de imagen no soportado.");
397
702
  }
703
+
704
+ // src/core/http.ts
705
+ init_errors();
706
+ init_envelope();
398
707
  var JumioHttpClient = class {
399
708
  client;
400
709
  config;
@@ -452,7 +761,7 @@ var JumioHttpClient = class {
452
761
  * Normaliza cualquier error de Axios a una excepción tipada JumioError.
453
762
  */
454
763
  normalizeError(error) {
455
- if (error instanceof JumioError) {
764
+ if (error instanceof exports.JumioError) {
456
765
  return error;
457
766
  }
458
767
  if (axios__default.default.isAxiosError(error)) {
@@ -461,18 +770,18 @@ var JumioHttpClient = class {
461
770
  const responseData = axiosErr.response?.data;
462
771
  const serverMessage = extractJumioMessage(responseData) || extractJumioMessage(axiosErr);
463
772
  if (axiosErr.code === "ECONNABORTED" || axiosErr.code === "ETIMEDOUT") {
464
- return new JumioTimeoutError(
773
+ return new exports.JumioTimeoutError(
465
774
  serverMessage || "La solicitud al servicio de Jumio excedi\xF3 el tiempo l\xEDmite.",
466
775
  responseData
467
776
  );
468
777
  }
469
778
  if (!axiosErr.response) {
470
- return new JumioNetworkError(
779
+ return new exports.JumioNetworkError(
471
780
  serverMessage || "No fue posible comunicarse con el servicio de Jumio.",
472
781
  axiosErr
473
782
  );
474
783
  }
475
- return new JumioError(serverMessage || `Error en la solicitud HTTP (${status}).`, {
784
+ return new exports.JumioError(serverMessage || `Error en la solicitud HTTP (${status}).`, {
476
785
  statusCode: status,
477
786
  rawData: responseData,
478
787
  code: axiosErr.code,
@@ -481,18 +790,18 @@ var JumioHttpClient = class {
481
790
  }
482
791
  if (error instanceof Error) {
483
792
  if (error.name === "AbortError") {
484
- return new JumioAbortError();
793
+ return new exports.JumioAbortError();
485
794
  }
486
- return new JumioError(error.message, { cause: error });
795
+ return new exports.JumioError(error.message, { cause: error });
487
796
  }
488
- return new JumioError("Ocurri\xF3 un error inesperado al contactar a Jumio.");
797
+ return new exports.JumioError("Ocurri\xF3 un error inesperado al contactar a Jumio.");
489
798
  }
490
799
  /**
491
800
  * Ejecuta una petición POST al endpoint de Jumio para iniciar o procesar la verificación.
492
801
  */
493
802
  async postVerification(payload, options) {
494
803
  if (options?.signal?.aborted) {
495
- throw new JumioAbortError();
804
+ throw new exports.JumioAbortError();
496
805
  }
497
806
  try {
498
807
  const dynamicHeaders = await this.resolveHeaders();
@@ -510,21 +819,26 @@ var JumioHttpClient = class {
510
819
  }
511
820
  /**
512
821
  * Ejecuta una petición GET para consultar el estado actual de una verificación de INE.
822
+ * Soporta un `clientId` opcional requerido por algunos endpoints de DynamiCore (p. ej. Hosted Webflow).
513
823
  */
514
824
  async getVerificationStatus(accountId, workflowId, options) {
515
825
  if (options?.signal?.aborted) {
516
- throw new JumioAbortError();
826
+ throw new exports.JumioAbortError();
517
827
  }
518
828
  try {
519
829
  const dynamicHeaders = await this.resolveHeaders();
520
830
  const endpoint = this.config.endpoint || "/marketplace/apps/jumio";
521
831
  const timeout = options?.timeout ?? this.config.statusTimeout ?? 12e4;
832
+ const queryParams = {
833
+ type: "ine",
834
+ accountId,
835
+ workflowId
836
+ };
837
+ if (options?.clientId) {
838
+ queryParams.clientId = options.clientId;
839
+ }
522
840
  const response = await this.client.get(endpoint, {
523
- params: {
524
- type: "ine",
525
- accountId,
526
- workflowId
527
- },
841
+ params: queryParams,
528
842
  headers: dynamicHeaders,
529
843
  timeout,
530
844
  signal: options?.signal
@@ -540,6 +854,9 @@ var JumioHttpClient = class {
540
854
  };
541
855
 
542
856
  // src/core/polling.ts
857
+ init_envelope();
858
+ init_errors();
859
+ init_retry();
543
860
  async function pollJumioStatus(http, accountId, workflowId, options = {}) {
544
861
  const config = http.getConfig();
545
862
  const maxAttempts = options.maxAttempts ?? config.maxPollingAttempts ?? 20;
@@ -548,7 +865,7 @@ async function pollJumioStatus(http, accountId, workflowId, options = {}) {
548
865
  let lastData = {};
549
866
  for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
550
867
  if (signal?.aborted) {
551
- throw new JumioAbortError();
868
+ throw new exports.JumioAbortError();
552
869
  }
553
870
  const responseData = await withRetry(
554
871
  () => http.getVerificationStatus(accountId, workflowId, {
@@ -592,10 +909,17 @@ async function pollJumioStatus(http, accountId, workflowId, options = {}) {
592
909
  }
593
910
  }
594
911
  const lastMessage = extractJumioMessage(lastData) || "La validaci\xF3n de INE sigue en proceso. Intenta nuevamente en unos momentos.";
595
- throw new JumioPollingTimeoutError(maxAttempts, lastMessage, lastData);
912
+ throw new exports.JumioPollingTimeoutError(maxAttempts, lastMessage, lastData);
596
913
  }
597
914
 
915
+ // src/core/index.ts
916
+ init_webflow();
917
+
598
918
  // src/core/client.ts
919
+ init_envelope();
920
+ init_errors();
921
+ init_retry();
922
+ init_webflow();
599
923
  var JumioClient = class {
600
924
  http;
601
925
  config;
@@ -609,10 +933,10 @@ var JumioClient = class {
609
933
  async startIneVerification(params) {
610
934
  const { clientId, frontImage, backImage, signal, onProgress } = params;
611
935
  if (!clientId || !clientId.trim()) {
612
- throw new JumioValidationError("Se requiere un identificador de cliente v\xE1lido (clientId).");
936
+ throw new exports.JumioValidationError("Se requiere un identificador de cliente v\xE1lido (clientId).");
613
937
  }
614
938
  if (signal?.aborted) {
615
- throw new JumioAbortError();
939
+ throw new exports.JumioAbortError();
616
940
  }
617
941
  onProgress?.("RESOLVING_IMAGES", 10);
618
942
  const [frontBase64, backBase64] = await Promise.all([
@@ -620,7 +944,7 @@ var JumioClient = class {
620
944
  resolveImageSourceToBase64(backImage, this.config.s3Signer, signal)
621
945
  ]);
622
946
  if (signal?.aborted) {
623
- throw new JumioAbortError();
947
+ throw new exports.JumioAbortError();
624
948
  }
625
949
  onProgress?.("SENDING_PAYLOAD", 40);
626
950
  const payload = {
@@ -708,7 +1032,7 @@ var JumioClient = class {
708
1032
  const workflowId = String(startData?.workflowId ?? "").trim();
709
1033
  if (!accountId || !workflowId) {
710
1034
  const errorMessage = extractJumioMessage(startData) || "No fue posible obtener los identificadores de seguimiento de la validaci\xF3n.";
711
- const error = new JumioError(errorMessage, { rawData: startData });
1035
+ const error = new exports.JumioError(errorMessage, { rawData: startData });
712
1036
  onStatusError?.(error);
713
1037
  throw error;
714
1038
  }
@@ -735,26 +1059,118 @@ var JumioClient = class {
735
1059
  onStatusResolved?.(finalResult);
736
1060
  return finalResult;
737
1061
  }
1062
+ // ─────────────────────────────────────────────────────────────────────────
1063
+ // Hosted Webflow (Redirección)
1064
+ // ─────────────────────────────────────────────────────────────────────────
1065
+ /**
1066
+ * Construye la URL de redirección de retorno para el flujo Hosted Webflow.
1067
+ *
1068
+ * Si el cliente está configurado con un `redirectProxyUrl` y `useProxy` es `true`,
1069
+ * la URL de retorno se codifica en Base64 URL-safe y se adjunta al proxy.
1070
+ *
1071
+ * @param returnUrl URL de la aplicación a la que Jumio redirigirá tras la verificación.
1072
+ * @param useProxy Si es `true` y hay `redirectProxyUrl` configurado, usa el proxy.
1073
+ * @returns URL de redirección construida.
1074
+ */
1075
+ buildRedirectUrl(returnUrl, useProxy = false) {
1076
+ const proxyUrl = useProxy ? this.config.redirectProxyUrl ?? void 0 : void 0;
1077
+ return buildRedirectUrl(returnUrl, proxyUrl);
1078
+ }
1079
+ /**
1080
+ * Inicia el flujo Hosted Webflow solicitando al backend de DynamiCore la URL
1081
+ * de verificación de Jumio (`href`).
1082
+ *
1083
+ * El usuario debe ser redirigido a esa URL para completar la verificación en la
1084
+ * página oficial de Jumio. Al terminar, Jumio redirige de vuelta a la aplicación
1085
+ * con `accountId` y `workflowExecutionId` como query params.
1086
+ *
1087
+ * @param input Parámetros del flujo: `clientId`, `successUrl`, `errorUrl`, opciones de proxy y redirección.
1088
+ * @returns `StartWebflowResult` con la URL de Jumio (`href`) y datos adicionales.
1089
+ *
1090
+ * @example
1091
+ * ```ts
1092
+ * const { href } = await client.startWebflow({
1093
+ * clientId: "usr_123",
1094
+ * successUrl: "https://app.example.com/verify/success",
1095
+ * errorUrl: "https://app.example.com/verify/error",
1096
+ * });
1097
+ * window.location.href = href;
1098
+ * ```
1099
+ */
1100
+ async startWebflow(input) {
1101
+ return startWebflowSession(this.http, this.config, input);
1102
+ }
1103
+ /**
1104
+ * Extrae los parámetros de seguimiento de Jumio de la URL de retorno.
1105
+ *
1106
+ * Jumio añade `accountId` y `workflowExecutionId` (o `workflowId`) como query
1107
+ * params al redirigir de vuelta a la aplicación tras la verificación.
1108
+ *
1109
+ * @param source URL completa, `URLSearchParams`, objeto con `search`/`href`, o nada para leer `window.location`.
1110
+ * @returns `WebflowReturnParams` con `accountId`, `workflowId`, `rawStatus` y todos los params.
1111
+ *
1112
+ * @example En React, en el componente de retorno:
1113
+ * ```ts
1114
+ * const { accountId, workflowId } = client.parseWebflowReturnParams(window.location.href);
1115
+ * ```
1116
+ */
1117
+ parseWebflowReturnParams(source) {
1118
+ return parseWebflowReturnParams(source);
1119
+ }
1120
+ /**
1121
+ * Consulta una única vez el estado actual de la verificación del flujo Hosted Webflow.
1122
+ *
1123
+ * @param input Parámetros de consulta: `accountId`, `workflowId`, y `clientId` opcional.
1124
+ * @returns `WebflowResult | null` — `null` si la verificación aún está pendiente.
1125
+ */
1126
+ async getWebflowStatus(input) {
1127
+ const { accountId, workflowId, clientId, signal } = input;
1128
+ const responseData = await this.http.getVerificationStatus(accountId, workflowId, {
1129
+ signal,
1130
+ timeout: this.config.statusTimeout,
1131
+ clientId
1132
+ });
1133
+ const firstLevel = extractEnvelopeData(responseData);
1134
+ const statusData = extractNestedData(firstLevel) ?? {};
1135
+ const { resolveWebflowResult: resolveWebflowResult2 } = await Promise.resolve().then(() => (init_webflow(), webflow_exports));
1136
+ return resolveWebflowResult2(statusData, accountId, workflowId);
1137
+ }
1138
+ /**
1139
+ * Sondea periódicamente el estado de verificación de un flujo Hosted Webflow de Jumio.
1140
+ *
1141
+ * Continúa consultando hasta obtener un resultado definitivo o agotar los intentos.
1142
+ *
1143
+ * @param params `accountId`, `workflowId` y `clientId` opcional.
1144
+ * @param options Opciones de sondeo (`maxAttempts`, `pollingIntervalMs`, `signal`, `onAttempt`).
1145
+ * @returns `WebflowResult` con el resultado definitivo.
1146
+ *
1147
+ * @example
1148
+ * ```ts
1149
+ * // En el componente de retorno, tras leer los params de la URL:
1150
+ * const result = await client.pollWebflowStatus({ accountId, workflowId, clientId });
1151
+ * if (result.valid) {
1152
+ * console.log("Verificación aprobada:", result.extraction);
1153
+ * } else {
1154
+ * console.warn("Rechazado:", result.errorMessage);
1155
+ * }
1156
+ * ```
1157
+ */
1158
+ async pollWebflowStatus(params, options) {
1159
+ return pollWebflowStatus(this.http, params, options);
1160
+ }
738
1161
  };
739
1162
  function createJumioClient(config) {
740
1163
  return new JumioClient(config);
741
1164
  }
742
1165
 
743
- exports.APPROVED_JUMIO_STATUSES = APPROVED_JUMIO_STATUSES;
744
- exports.FINAL_JUMIO_STATUSES = FINAL_JUMIO_STATUSES;
745
- exports.JumioAbortError = JumioAbortError;
746
1166
  exports.JumioClient = JumioClient;
747
- exports.JumioError = JumioError;
748
1167
  exports.JumioHttpClient = JumioHttpClient;
749
- exports.JumioImageProcessingError = JumioImageProcessingError;
750
- exports.JumioNetworkError = JumioNetworkError;
751
- exports.JumioPollingTimeoutError = JumioPollingTimeoutError;
752
- exports.JumioTimeoutError = JumioTimeoutError;
753
- exports.JumioValidationError = JumioValidationError;
754
1168
  exports.arrayBufferToBase64 = arrayBufferToBase64;
755
1169
  exports.blobToBase64 = blobToBase64;
1170
+ exports.buildRedirectUrl = buildRedirectUrl;
756
1171
  exports.createJumioClient = createJumioClient;
757
1172
  exports.delay = delay;
1173
+ exports.encodeUrlToBase64UrlSafe = encodeUrlToBase64UrlSafe;
758
1174
  exports.extractEnvelopeData = extractEnvelopeData;
759
1175
  exports.extractJumioMessage = extractJumioMessage;
760
1176
  exports.extractNestedData = extractNestedData;
@@ -765,10 +1181,14 @@ exports.isFinalJumioStatus = isFinalJumioStatus;
765
1181
  exports.isJumioError = isJumioError;
766
1182
  exports.isPassedJumioDecision = isPassedJumioDecision;
767
1183
  exports.normalizeSignedUrl = normalizeSignedUrl;
1184
+ exports.parseWebflowReturnParams = parseWebflowReturnParams;
768
1185
  exports.pollJumioStatus = pollJumioStatus;
1186
+ exports.pollWebflowStatus = pollWebflowStatus;
769
1187
  exports.resolveImageSourceToBase64 = resolveImageSourceToBase64;
770
1188
  exports.resolveVerificationValidity = resolveVerificationValidity;
1189
+ exports.resolveWebflowResult = resolveWebflowResult;
771
1190
  exports.shouldRetryJumio = shouldRetryJumio;
1191
+ exports.startWebflowSession = startWebflowSession;
772
1192
  exports.stripDataUrlPrefix = stripDataUrlPrefix;
773
1193
  exports.toLowerText = toLowerText;
774
1194
  exports.toUpperText = toUpperText;