@fire-spark/payments-clisitef-pinpad-rn 0.8.2 → 0.8.3
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.
- package/dist/index.d.ts +6 -6
- package/dist/index.js +65 -29
- package/package.json +4 -4
package/dist/index.d.ts
CHANGED
|
@@ -17,6 +17,8 @@ type ClisitefPinPadOptions = {
|
|
|
17
17
|
timeZone?: string;
|
|
18
18
|
now?: () => Date;
|
|
19
19
|
confirmationTimeoutMs?: number;
|
|
20
|
+
/** Wait for the `stage 1` of a released leftover routine; defaults to 15 s. */
|
|
21
|
+
releaseTimeoutMs?: number;
|
|
20
22
|
/**
|
|
21
23
|
* Payment deadline (`policy.timeout_ms`); defaults to 180 s. A
|
|
22
24
|
* `runtime.timeout_ms` in the payment or method config overrides it.
|
|
@@ -66,13 +68,11 @@ declare const CLISITEF_COMMAND: {
|
|
|
66
68
|
/** `continueTransaction` answers to `CONFIRM` (20). */
|
|
67
69
|
declare const CLISITEF_YES = "0";
|
|
68
70
|
declare const CLISITEF_NO = "1";
|
|
69
|
-
/** `continueTransaction` answer to `CHECK_ABORT` (23): interrupt. */
|
|
70
|
-
declare const CLISITEF_INTERRUPT = "1";
|
|
71
71
|
/**
|
|
72
|
-
*
|
|
73
|
-
*
|
|
72
|
+
* Wait for the `stage 1` of a routine a previous charge left open, after
|
|
73
|
+
* answering it with `abortTransaction(-1)`; then the charge starts anyway.
|
|
74
74
|
*/
|
|
75
|
-
declare const
|
|
75
|
+
declare const CLISITEF_RELEASE_TIMEOUT_MS = 15000;
|
|
76
76
|
/** `TipoCampo` ids stored with `STORE_FIELD` (Fiserv "Tabela TipoCampo"). */
|
|
77
77
|
declare const CLISITEF_FIELD: {
|
|
78
78
|
readonly TRANSACTION_DATE: 105;
|
|
@@ -350,4 +350,4 @@ type ClisitefTransactionInput = {
|
|
|
350
350
|
*/
|
|
351
351
|
declare const runClisitefTransaction: (input: ClisitefTransactionInput) => Promise<ClisitefOutcome>;
|
|
352
352
|
//#endregion
|
|
353
|
-
export { CLISITEF_CANCEL_CODES, CLISITEF_CAPTURE_FIELDS, CLISITEF_COMMAND, CLISITEF_CONFIRMATION_TIMEOUT_MS, CLISITEF_DEFAULT_OPERATOR,
|
|
353
|
+
export { CLISITEF_CANCEL_CODES, CLISITEF_CAPTURE_FIELDS, CLISITEF_COMMAND, CLISITEF_CONFIRMATION_TIMEOUT_MS, CLISITEF_DEFAULT_OPERATOR, CLISITEF_FIELD, CLISITEF_INCONCLUSIVE_CODES, CLISITEF_MODALITIES, CLISITEF_NO, CLISITEF_PAYMENT_TIMEOUT_MS, CLISITEF_PINPAD_TYPES, CLISITEF_REFUNDS_KEY, CLISITEF_REFUND_STORAGE_KEY, CLISITEF_RELEASE_TIMEOUT_MS, CLISITEF_REVERSALS_KEY, CLISITEF_STORAGE_KEY, CLISITEF_VOID_FIELD, CLISITEF_YES, ClisitefFields, ClisitefMenuDecision, ClisitefMenuPurpose, ClisitefModality, ClisitefOutcome, ClisitefOutcomeStatus, ClisitefPendingReversal, ClisitefPinPadOptions, ClisitefPinPadSettings, ClisitefProviderMetadata, ClisitefTransactionInput, ClisitefTransactionRecord, ClisitefTransactionState, ClisitefVoidContext, ClisitefVoidDeps, clisitefDetails, clisitefLast4, clisitefMetadata, clisitefModalityOf, clisitefPinPadCapabilities, clisitefPinPadDeviceFields, clisitefPinPadErrors, clisitefPinPadPayments, clisitefVoidMetadata, dropReversal, isClisitefModality, isOpen, queueReversal, readClisitefPinPadSettings, readPendingReversals, readRefund, readTransaction, redactSecrets, resolveClisitefMenu, runClisitefTransaction, runClisitefVoid, writeRefund, writeTransaction };
|
package/dist/index.js
CHANGED
|
@@ -34,13 +34,11 @@ const CLISITEF_COMMAND = {
|
|
|
34
34
|
/** `continueTransaction` answers to `CONFIRM` (20). */
|
|
35
35
|
const CLISITEF_YES = "0";
|
|
36
36
|
const CLISITEF_NO = "1";
|
|
37
|
-
/** `continueTransaction` answer to `CHECK_ABORT` (23): interrupt. */
|
|
38
|
-
const CLISITEF_INTERRUPT = "1";
|
|
39
37
|
/**
|
|
40
|
-
*
|
|
41
|
-
*
|
|
38
|
+
* Wait for the `stage 1` of a routine a previous charge left open, after
|
|
39
|
+
* answering it with `abortTransaction(-1)`; then the charge starts anyway.
|
|
42
40
|
*/
|
|
43
|
-
const
|
|
41
|
+
const CLISITEF_RELEASE_TIMEOUT_MS = 15e3;
|
|
44
42
|
/** `TipoCampo` ids stored with `STORE_FIELD` (Fiserv "Tabela TipoCampo"). */
|
|
45
43
|
const CLISITEF_FIELD = {
|
|
46
44
|
TRANSACTION_DATE: 105,
|
|
@@ -468,7 +466,6 @@ const runClisitefTransaction = (input) => {
|
|
|
468
466
|
let aborted = false;
|
|
469
467
|
/** Why the adapter asked to interrupt; `stage 1` has not arrived yet. */
|
|
470
468
|
let givingUp = null;
|
|
471
|
-
let drained = 0;
|
|
472
469
|
let watchdog;
|
|
473
470
|
let queue = Promise.resolve();
|
|
474
471
|
let resolve = () => void 0;
|
|
@@ -517,20 +514,22 @@ const runClisitefTransaction = (input) => {
|
|
|
517
514
|
});
|
|
518
515
|
}
|
|
519
516
|
};
|
|
520
|
-
/**
|
|
517
|
+
/**
|
|
518
|
+
* Stops waiting: `stage 1` never came. The routine may still be open in
|
|
519
|
+
* CliSiTef; the next charge releases it (`open` outcome).
|
|
520
|
+
*/
|
|
521
521
|
const abandon = () => {
|
|
522
|
-
log("abandon", {
|
|
523
|
-
drained,
|
|
524
|
-
skipped: closing
|
|
525
|
-
});
|
|
522
|
+
log("abandon", { skipped: closing });
|
|
526
523
|
if (closing || !givingUp) return;
|
|
527
524
|
closing = true;
|
|
528
525
|
settle("open", givingUp);
|
|
529
526
|
};
|
|
530
527
|
/**
|
|
531
|
-
*
|
|
532
|
-
*
|
|
533
|
-
*
|
|
528
|
+
* Marks the transaction to interrupt. CliSiTef only takes `Continua = -1`
|
|
529
|
+
* as the answer to an `onData` (Interface Simplificada §5.3), so nothing is
|
|
530
|
+
* sent here: the pending or next event is answered with
|
|
531
|
+
* `abortTransaction(-1)` until `stage 1`. An approval already confirmed
|
|
532
|
+
* with `finishTransaction(1)` is undone instead.
|
|
534
533
|
*/
|
|
535
534
|
const giveUp = (reason) => {
|
|
536
535
|
log("give up", reason);
|
|
@@ -542,7 +541,6 @@ const runClisitefTransaction = (input) => {
|
|
|
542
541
|
}
|
|
543
542
|
givingUp = reason;
|
|
544
543
|
watchdog = setTimeout(abandon, input.confirmationTimeoutMs);
|
|
545
|
-
client.abortTransaction(CLISITEF_ABORT_FLAG).catch(() => 0);
|
|
546
544
|
};
|
|
547
545
|
function onAbort() {
|
|
548
546
|
log("signal aborted (payment deadline)");
|
|
@@ -573,19 +571,21 @@ const runClisitefTransaction = (input) => {
|
|
|
573
571
|
expiresAt: null
|
|
574
572
|
});
|
|
575
573
|
};
|
|
576
|
-
/**
|
|
574
|
+
/**
|
|
575
|
+
* Answers every event after giving up with `Continua = -1`, without the UI
|
|
576
|
+
* and without a count: a `continueTransaction` here would tell CliSiTef to
|
|
577
|
+
* keep going (PIX keeps polling the server for minutes).
|
|
578
|
+
*/
|
|
577
579
|
const drain = async (event) => {
|
|
578
|
-
drained += 1;
|
|
579
580
|
log("drain", {
|
|
580
581
|
command: event.command,
|
|
581
|
-
|
|
582
|
+
skipped: closing
|
|
582
583
|
});
|
|
583
|
-
if (drained > 10) return abandon();
|
|
584
584
|
const { command } = event;
|
|
585
585
|
if (command === CLISITEF_COMMAND.STORE_FIELD) store(event);
|
|
586
586
|
if (command === CLISITEF_COMMAND.QR_HIDE) clearQr();
|
|
587
|
-
|
|
588
|
-
|
|
587
|
+
if (closing) return;
|
|
588
|
+
await client.abortTransaction(CLISITEF_ABORT_FLAG);
|
|
589
589
|
};
|
|
590
590
|
/** A UI answer that arrives after giving up is not sent. */
|
|
591
591
|
const respond = (event, data) => {
|
|
@@ -1378,7 +1378,10 @@ const clisitefPinPadPayments = (options = {}) => {
|
|
|
1378
1378
|
const now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
1379
1379
|
const confirmationMs = options.confirmationTimeoutMs ?? 6e4;
|
|
1380
1380
|
const timeoutMs = options.timeoutMs ?? 18e4;
|
|
1381
|
+
const releaseMs = options.releaseTimeoutMs ?? 15e3;
|
|
1381
1382
|
const lock = createLock();
|
|
1383
|
+
/** A charge of this process gave up without `stage 1` (`open`). */
|
|
1384
|
+
let leftOpen = false;
|
|
1382
1385
|
const storageOf = (ctx) => {
|
|
1383
1386
|
return options.storage ?? ctx.storage;
|
|
1384
1387
|
};
|
|
@@ -1455,12 +1458,38 @@ const clisitefPinPadPayments = (options = {}) => {
|
|
|
1455
1458
|
return error?.provider_code === "-12";
|
|
1456
1459
|
};
|
|
1457
1460
|
/**
|
|
1458
|
-
*
|
|
1459
|
-
* `
|
|
1460
|
-
*
|
|
1461
|
+
* Ends an iterative routine left open in this process (`-12`). CliSiTef
|
|
1462
|
+
* takes `Continua = -1` only as the answer to an `onData`, so the pending
|
|
1463
|
+
* event and every new one get `abortTransaction(-1)` until the routine's
|
|
1464
|
+
* `stage 1`, which is dropped. No `submitPendingMessages` or `closePinPad`
|
|
1465
|
+
* here: right after an abort they left the native thread hung in production.
|
|
1461
1466
|
*/
|
|
1462
|
-
const
|
|
1463
|
-
|
|
1467
|
+
const releaseRoutine = () => {
|
|
1468
|
+
clisitefDebug("pinpad.adapter.release", "routine", { releaseMs });
|
|
1469
|
+
leftOpen = false;
|
|
1470
|
+
const subscriptions = [];
|
|
1471
|
+
let timer;
|
|
1472
|
+
const abort = () => {
|
|
1473
|
+
client.abortTransaction(CLISITEF_ABORT_FLAG).catch(() => 0);
|
|
1474
|
+
};
|
|
1475
|
+
return new Promise((resolve) => {
|
|
1476
|
+
const done = () => {
|
|
1477
|
+
clearTimeout(timer);
|
|
1478
|
+
for (const subscription of subscriptions) subscription.remove();
|
|
1479
|
+
client.invalidate();
|
|
1480
|
+
resolve();
|
|
1481
|
+
};
|
|
1482
|
+
subscriptions.push(client.onData(abort));
|
|
1483
|
+
subscriptions.push(client.onTransactionResult((event) => {
|
|
1484
|
+
if (event.stage === 1) done();
|
|
1485
|
+
}));
|
|
1486
|
+
timer = setTimeout(done, releaseMs);
|
|
1487
|
+
abort();
|
|
1488
|
+
});
|
|
1489
|
+
};
|
|
1490
|
+
/** `startTransaction` refused: a previous routine is still open. */
|
|
1491
|
+
const isStartBusy = (outcome) => {
|
|
1492
|
+
return outcome.status === "declined" && outcome.code === -12 && !outcome.aborted && outcome.fields.size === 0;
|
|
1464
1493
|
};
|
|
1465
1494
|
/** Open, or flagged for review with the coupon maybe still pending. */
|
|
1466
1495
|
const recoverable = (record) => {
|
|
@@ -1469,10 +1498,11 @@ const clisitefPinPadPayments = (options = {}) => {
|
|
|
1469
1498
|
/** Configures and resolves the open records of the device, if any. */
|
|
1470
1499
|
const prepare = async (ctx) => {
|
|
1471
1500
|
const settings = readClisitefPinPadSettings(ctx.config, ctx.deviceSettings);
|
|
1501
|
+
if (leftOpen) await releaseRoutine();
|
|
1472
1502
|
let error = await configure(settings);
|
|
1473
1503
|
if (isConfigureBusy(error)) {
|
|
1474
1504
|
clisitefDebug("pinpad.adapter.release", "busy", {});
|
|
1475
|
-
await
|
|
1505
|
+
await releaseRoutine();
|
|
1476
1506
|
error = await configure(settings);
|
|
1477
1507
|
}
|
|
1478
1508
|
const storage = storageOf(ctx);
|
|
@@ -1598,11 +1628,17 @@ const clisitefPinPadPayments = (options = {}) => {
|
|
|
1598
1628
|
modality: chosen,
|
|
1599
1629
|
purpose: "charge"
|
|
1600
1630
|
};
|
|
1601
|
-
const
|
|
1631
|
+
const run = () => runClisitefTransaction({
|
|
1602
1632
|
...t1,
|
|
1603
1633
|
...t2,
|
|
1604
1634
|
...t3
|
|
1605
1635
|
});
|
|
1636
|
+
let outcome = await run();
|
|
1637
|
+
if (isStartBusy(outcome)) {
|
|
1638
|
+
await releaseRoutine();
|
|
1639
|
+
if (!await configure(settings)) outcome = await run();
|
|
1640
|
+
}
|
|
1641
|
+
if (outcome.status === "open") leftOpen = true;
|
|
1606
1642
|
const fields = Object.fromEntries(outcome.fields);
|
|
1607
1643
|
clisitefDebug("pinpad.adapter.charge", "outcome", {
|
|
1608
1644
|
...outcome,
|
|
@@ -1822,4 +1858,4 @@ const clisitefPinPadPayments = (options = {}) => {
|
|
|
1822
1858
|
};
|
|
1823
1859
|
};
|
|
1824
1860
|
//#endregion
|
|
1825
|
-
export { CLISITEF_CANCEL_CODES, CLISITEF_CAPTURE_FIELDS, CLISITEF_COMMAND, CLISITEF_CONFIRMATION_TIMEOUT_MS, CLISITEF_DEFAULT_OPERATOR,
|
|
1861
|
+
export { CLISITEF_CANCEL_CODES, CLISITEF_CAPTURE_FIELDS, CLISITEF_COMMAND, CLISITEF_CONFIRMATION_TIMEOUT_MS, CLISITEF_DEFAULT_OPERATOR, CLISITEF_FIELD, CLISITEF_INCONCLUSIVE_CODES, CLISITEF_MODALITIES, CLISITEF_NO, CLISITEF_PAYMENT_TIMEOUT_MS, CLISITEF_PINPAD_TYPES, CLISITEF_REFUNDS_KEY, CLISITEF_REFUND_STORAGE_KEY, CLISITEF_RELEASE_TIMEOUT_MS, CLISITEF_REVERSALS_KEY, CLISITEF_STORAGE_KEY, CLISITEF_VOID_FIELD, CLISITEF_YES, clisitefDetails, clisitefLast4, clisitefMetadata, clisitefModalityOf, clisitefPinPadCapabilities, clisitefPinPadDeviceFields, clisitefPinPadErrors, clisitefPinPadPayments, clisitefVoidMetadata, dropReversal, isClisitefModality, isOpen, queueReversal, readClisitefPinPadSettings, readPendingReversals, readRefund, readTransaction, redactSecrets, resolveClisitefMenu, runClisitefTransaction, runClisitefVoid, writeRefund, writeTransaction };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fire-spark/payments-clisitef-pinpad-rn",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.3",
|
|
4
4
|
"description": "Fire Spark CliSiTef (Software Express) pinpad adapter for Brazil: debit, credit, voucher and Pix with automatic voids on Android kiosks",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -17,9 +17,9 @@
|
|
|
17
17
|
}
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@fire-spark/payments": "^0.8.
|
|
21
|
-
"@fire-spark/payments-clisitef-client": "^0.8.
|
|
22
|
-
"@fire-spark/types": "^0.8.
|
|
20
|
+
"@fire-spark/payments": "^0.8.3",
|
|
21
|
+
"@fire-spark/payments-clisitef-client": "^0.8.3",
|
|
22
|
+
"@fire-spark/types": "^0.8.3"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"tsdown": "^0.22.14",
|