@fire-spark/payments-clisitef-pinpad-rn 0.0.0-stage → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,207 @@
1
+ import { DeviceField, PaymentAdapter, PaymentAdapterCapabilities, PaymentErrorEntry, PaymentMetadata, PaymentStorage, PaymentUI, StandardPaymentError } from "@fire-spark/payments";
2
+ import { CLISITEF_MODALITY, ClisitefClient, ClisitefConfigureParams, ClisitefFinishParams, ClisitefStartParams } from "@fire-spark/payments-clisitef-client";
3
+ import { TenderDetails } from "@fire-spark/types";
4
+ //#region src/adapter.d.ts
5
+ /** Confirmed in the act (`finishTransaction(1)`), never captured later. */
6
+ declare const clisitefPinPadCapabilities: PaymentAdapterCapabilities;
7
+ type ClisitefPinPadOptions = {
8
+ /** Defaults to the shared client bound to the native module. */
9
+ client?: ClisitefClient;
10
+ /**
11
+ * Device-wide storage for the pending-transaction record. Defaults to
12
+ * `ctx.storage`, which is scoped per payment: a transaction left open by
13
+ * the DEBIT payment is then not seen by the CREDIT one.
14
+ */
15
+ storage?: PaymentStorage;
16
+ /** Store time zone for the fiscal date; defaults to `America/Sao_Paulo`. */
17
+ timeZone?: string;
18
+ now?: () => Date;
19
+ confirmationTimeoutMs?: number;
20
+ };
21
+ /**
22
+ * CliSiTef (Software Express) on the kiosk pinpad, Brazil. One adapter per
23
+ * modality payment (DEBIT / CREDIT / VOUCHER in `payments.config`). The
24
+ * pinpad waits on the customer: give the payment a `runtime.timeout_ms`
25
+ * well above the 30 s default (e.g. 90 000).
26
+ */
27
+ declare const clisitefPinPadPayments: (options?: ClisitefPinPadOptions) => PaymentAdapter;
28
+ //#endregion
29
+ //#region src/constants.d.ts
30
+ /**
31
+ * `onData` commands handled by the adapter (Fiserv "Tabela de códigos de
32
+ * comando"). Not handled, so they abort the transaction: 29 (silent field),
33
+ * 31 (check), 35 (barcode), 42 (identified menu, only with
34
+ * `ItemMenuIdentificado`) and 50/51 (QR, PIX only).
35
+ */
36
+ declare const CLISITEF_COMMAND: {
37
+ readonly STORE_FIELD: 0;
38
+ readonly MESSAGE_OPERATOR: 1;
39
+ readonly MESSAGE_CUSTOMER: 2;
40
+ readonly MESSAGE_BOTH: 3;
41
+ readonly MENU_TITLE: 4;
42
+ readonly CLEAR_OPERATOR: 11;
43
+ readonly CLEAR_CUSTOMER: 12;
44
+ readonly CLEAR_BOTH: 13;
45
+ readonly CLEAR_MENU_TITLE: 14;
46
+ readonly HEADER: 15;
47
+ readonly CLEAR_HEADER: 16;
48
+ readonly CONFIRM: 20;
49
+ readonly MENU: 21;
50
+ readonly PRESS_KEY: 22;
51
+ readonly CHECK_ABORT: 23;
52
+ readonly READ_FIELD: 30;
53
+ readonly READ_AMOUNT: 34;
54
+ readonly READ_MASKED: 41;
55
+ readonly FOOTER: 52;
56
+ };
57
+ /** `continueTransaction` answers to `CONFIRM` (20). */
58
+ declare const CLISITEF_YES = "0";
59
+ declare const CLISITEF_NO = "1";
60
+ /** `TipoCampo` ids stored with `STORE_FIELD` (Fiserv "Tabela TipoCampo"). */
61
+ declare const CLISITEF_FIELD: {
62
+ readonly TRANSACTION_DATE: 105;
63
+ readonly CUSTOMER_RECEIPT: 121;
64
+ readonly MERCHANT_RECEIPT: 122;
65
+ readonly INSTITUTION_CODE: 131;
66
+ readonly CARD_TYPE_CODE: 132;
67
+ readonly SITEF_NSU: 133;
68
+ readonly HOST_NSU: 134;
69
+ readonly AUTHORIZATION_CODE: 135;
70
+ readonly CARD_BIN: 136;
71
+ readonly INSTITUTION_NAME: 156;
72
+ readonly LAST4: 1190;
73
+ readonly ENTRY_MODE: 2090;
74
+ };
75
+ /** Fields that prove the card was read: an error after them is ambiguous. */
76
+ declare const CLISITEF_CAPTURE_FIELDS: ReadonlySet<number>;
77
+ /** Operator, pinpad or automation cancelled (ficha §11). */
78
+ declare const CLISITEF_CANCEL_CODES: ReadonlySet<number>;
79
+ /** Inconclusive when the card was already read (ficha §4). */
80
+ declare const CLISITEF_INCONCLUSIVE_CODES: ReadonlySet<number>;
81
+ /** Approved (`stage 1`) without `stage 2`: undo (legacy `CONFIRMATION_TIMEOUT_MS`). */
82
+ declare const CLISITEF_CONFIRMATION_TIMEOUT_MS = 60000;
83
+ /** Legacy operator when the merchant config has none. */
84
+ declare const CLISITEF_DEFAULT_OPERATOR = "KIOSKO_BR";
85
+ /** Device-wide record of the last transaction, to undo it after a crash. */
86
+ declare const CLISITEF_STORAGE_KEY = "clisitef:transaction:v1";
87
+ //#endregion
88
+ //#region src/errors.d.ts
89
+ /**
90
+ * Ficha §11 (Fiserv "Tabela de códigos de retorno"); other positive codes
91
+ * (authorizer) fall back to `CARD_DECLINED`, other negatives to `UNKNOWN`.
92
+ */
93
+ declare const clisitefPinPadErrors: Readonly<Record<string, PaymentErrorEntry>> & {
94
+ "-1": PaymentErrorEntry;
95
+ "-2": PaymentErrorEntry;
96
+ "-3": PaymentErrorEntry;
97
+ "-4": PaymentErrorEntry;
98
+ "-5": PaymentErrorEntry;
99
+ "-6": PaymentErrorEntry;
100
+ "-8": PaymentErrorEntry;
101
+ "-9": PaymentErrorEntry;
102
+ "-10": PaymentErrorEntry;
103
+ "-12": PaymentErrorEntry;
104
+ "-13": PaymentErrorEntry;
105
+ "-15": PaymentErrorEntry;
106
+ "-20": PaymentErrorEntry;
107
+ "-21": PaymentErrorEntry;
108
+ "-24": PaymentErrorEntry;
109
+ "-30": PaymentErrorEntry;
110
+ "-40": PaymentErrorEntry;
111
+ "-41": PaymentErrorEntry;
112
+ "-43": PaymentErrorEntry;
113
+ "-50": PaymentErrorEntry;
114
+ "-100": PaymentErrorEntry;
115
+ CLISITEF_TIMEOUT: PaymentErrorEntry;
116
+ };
117
+ //#endregion
118
+ //#region src/settings.d.ts
119
+ declare const CLISITEF_PINPAD_TYPES: readonly ["ANDROID_USB", "ANDROID_BT", "ANDROID_AUTO"];
120
+ /** Ficha §6: filled per kiosk in the device settings. */
121
+ declare const clisitefPinPadDeviceFields: DeviceField[];
122
+ type ClisitefModality = keyof typeof CLISITEF_MODALITY;
123
+ type ClisitefPinPadSettings = {
124
+ configure: ClisitefConfigureParams;
125
+ modality: Exclude<ClisitefModality, "PIX">;
126
+ operator: string;
127
+ restrictions: string;
128
+ terminalNumber: string;
129
+ };
130
+ /** `payments.config` (merchant) + device settings; throws when incomplete. */
131
+ declare const readClisitefPinPadSettings: (config: Record<string, unknown>, device: Record<string, unknown>) => ClisitefPinPadSettings;
132
+ //#endregion
133
+ //#region src/metadata.d.ts
134
+ type ClisitefFields = ReadonlyMap<number, string>;
135
+ /** Last 4 digits of the masked PAN printed on the receipt. */
136
+ declare const clisitefLast4: (receipt: string | null) => string | null;
137
+ type MetadataInput = {
138
+ attemptReference: string;
139
+ fields: ClisitefFields;
140
+ modality: ClisitefModality;
141
+ terminalNumber: string;
142
+ fiscalCoupon: string;
143
+ fiscalDate: string;
144
+ };
145
+ declare const clisitefMetadata: (input: MetadataInput) => PaymentMetadata;
146
+ /** PIN_PAD tender details; `null` without brand and last 4 (schema minimum). */
147
+ declare const clisitefDetails: (metadata: PaymentMetadata) => TenderDetails | null;
148
+ //#endregion
149
+ //#region src/store.d.ts
150
+ /**
151
+ * `started`: `startTransaction` called. `approved`: `finishTransaction(1)`
152
+ * called, no `stage 2` yet. `confirmed` / `undone`: closed either way.
153
+ * `review`: approved, then lost, and no longer pending in CliSiTef: it may
154
+ * have been charged.
155
+ */
156
+ type ClisitefTransactionState = "started" | "approved" | "confirmed" | "undone" | "review";
157
+ type ClisitefTransactionRecord = {
158
+ attemptReference: string;
159
+ fiscalCoupon: string;
160
+ fiscalDate: string;
161
+ time: string;
162
+ startedAt: number;
163
+ state: ClisitefTransactionState;
164
+ amount: number;
165
+ metadata?: PaymentMetadata;
166
+ details?: TenderDetails | null;
167
+ error?: StandardPaymentError;
168
+ };
169
+ declare const readTransaction: (storage: PaymentStorage) => Promise<ClisitefTransactionRecord | null>;
170
+ declare const writeTransaction: (storage: PaymentStorage, record: ClisitefTransactionRecord) => Promise<void>;
171
+ declare const isOpen: (record: ClisitefTransactionRecord) => boolean;
172
+ //#endregion
173
+ //#region src/transaction.d.ts
174
+ /**
175
+ * `confirmed`: `stage 2` closed with 0. `declined`: failed before the card
176
+ * was charged. `undone`: `finishTransaction(0)` sent after a capture or an
177
+ * approval. `unresolved`: the undo itself failed; needs review.
178
+ */
179
+ type ClisitefOutcomeStatus = "confirmed" | "declined" | "undone" | "unresolved";
180
+ type ClisitefOutcome = {
181
+ status: ClisitefOutcomeStatus;
182
+ /** Provider code: `resultCode`, a client error code, or `null`. */
183
+ code: number | string | null;
184
+ message: string | null;
185
+ fields: ClisitefFields;
186
+ aborted: boolean;
187
+ /** Error thrown by `ctx.ui` (e.g. the customer did not answer). */
188
+ error?: unknown;
189
+ };
190
+ type ClisitefTransactionInput = {
191
+ client: ClisitefClient;
192
+ ui: PaymentUI;
193
+ signal: AbortSignal;
194
+ start: ClisitefStartParams;
195
+ finish: Omit<ClisitefFinishParams, "confirm">;
196
+ confirmationTimeoutMs: number;
197
+ /** Runs before `finishTransaction(1)`, to persist the approval. */
198
+ onApproved: (fields: ClisitefFields) => Promise<void>;
199
+ };
200
+ /**
201
+ * One CliSiTef transaction: `startTransaction`, the `onData` loop answered
202
+ * through `ui`, `finishTransaction(1)` on approval (`stage 1` = 0) and
203
+ * success only when `stage 2` closes with 0. Never rejects.
204
+ */
205
+ declare const runClisitefTransaction: (input: ClisitefTransactionInput) => Promise<ClisitefOutcome>;
206
+ //#endregion
207
+ export { CLISITEF_CANCEL_CODES, CLISITEF_CAPTURE_FIELDS, CLISITEF_COMMAND, CLISITEF_CONFIRMATION_TIMEOUT_MS, CLISITEF_DEFAULT_OPERATOR, CLISITEF_FIELD, CLISITEF_INCONCLUSIVE_CODES, CLISITEF_NO, CLISITEF_PINPAD_TYPES, CLISITEF_STORAGE_KEY, CLISITEF_YES, ClisitefFields, ClisitefModality, ClisitefOutcome, ClisitefOutcomeStatus, ClisitefPinPadOptions, ClisitefPinPadSettings, ClisitefTransactionInput, ClisitefTransactionRecord, ClisitefTransactionState, clisitefDetails, clisitefLast4, clisitefMetadata, clisitefPinPadCapabilities, clisitefPinPadDeviceFields, clisitefPinPadErrors, clisitefPinPadPayments, isOpen, readClisitefPinPadSettings, readTransaction, runClisitefTransaction, writeTransaction };
package/dist/index.js ADDED
@@ -0,0 +1,977 @@
1
+ import { PaymentError, createPaymentError, definePaymentErrors, toPaymentError } from "@fire-spark/payments";
2
+ import { CLISITEF_ABORT_FLAG, CLISITEF_CONFIRM, CLISITEF_MODALITY, CLISITEF_RESULT, CLISITEF_TIMEOUT_CODE, clisitef, clisitefAdditionalParams, clisitefFiscalDateTime, formatClisitefAmount, parseClisitefMenu } from "@fire-spark/payments-clisitef-client";
3
+ //#region src/constants.ts
4
+ /**
5
+ * `onData` commands handled by the adapter (Fiserv "Tabela de códigos de
6
+ * comando"). Not handled, so they abort the transaction: 29 (silent field),
7
+ * 31 (check), 35 (barcode), 42 (identified menu, only with
8
+ * `ItemMenuIdentificado`) and 50/51 (QR, PIX only).
9
+ */
10
+ const CLISITEF_COMMAND = {
11
+ STORE_FIELD: 0,
12
+ MESSAGE_OPERATOR: 1,
13
+ MESSAGE_CUSTOMER: 2,
14
+ MESSAGE_BOTH: 3,
15
+ MENU_TITLE: 4,
16
+ CLEAR_OPERATOR: 11,
17
+ CLEAR_CUSTOMER: 12,
18
+ CLEAR_BOTH: 13,
19
+ CLEAR_MENU_TITLE: 14,
20
+ HEADER: 15,
21
+ CLEAR_HEADER: 16,
22
+ CONFIRM: 20,
23
+ MENU: 21,
24
+ PRESS_KEY: 22,
25
+ CHECK_ABORT: 23,
26
+ READ_FIELD: 30,
27
+ READ_AMOUNT: 34,
28
+ READ_MASKED: 41,
29
+ FOOTER: 52
30
+ };
31
+ /** `continueTransaction` answers to `CONFIRM` (20). */
32
+ const CLISITEF_YES = "0";
33
+ const CLISITEF_NO = "1";
34
+ /** `TipoCampo` ids stored with `STORE_FIELD` (Fiserv "Tabela TipoCampo"). */
35
+ const CLISITEF_FIELD = {
36
+ TRANSACTION_DATE: 105,
37
+ CUSTOMER_RECEIPT: 121,
38
+ MERCHANT_RECEIPT: 122,
39
+ INSTITUTION_CODE: 131,
40
+ CARD_TYPE_CODE: 132,
41
+ SITEF_NSU: 133,
42
+ HOST_NSU: 134,
43
+ AUTHORIZATION_CODE: 135,
44
+ CARD_BIN: 136,
45
+ INSTITUTION_NAME: 156,
46
+ LAST4: 1190,
47
+ ENTRY_MODE: 2090
48
+ };
49
+ /** Fields that prove the card was read: an error after them is ambiguous. */
50
+ const CLISITEF_CAPTURE_FIELDS = /* @__PURE__ */ new Set([
51
+ CLISITEF_FIELD.CUSTOMER_RECEIPT,
52
+ CLISITEF_FIELD.MERCHANT_RECEIPT,
53
+ CLISITEF_FIELD.CARD_TYPE_CODE,
54
+ CLISITEF_FIELD.HOST_NSU,
55
+ CLISITEF_FIELD.AUTHORIZATION_CODE,
56
+ CLISITEF_FIELD.CARD_BIN,
57
+ CLISITEF_FIELD.LAST4,
58
+ CLISITEF_FIELD.ENTRY_MODE
59
+ ]);
60
+ /** Operator, pinpad or automation cancelled (ficha §11). */
61
+ const CLISITEF_CANCEL_CODES = /* @__PURE__ */ new Set([
62
+ -2,
63
+ -6,
64
+ -15
65
+ ]);
66
+ /** Inconclusive when the card was already read (ficha §4). */
67
+ const CLISITEF_INCONCLUSIVE_CODES = /* @__PURE__ */ new Set([
68
+ -5,
69
+ -43,
70
+ -100
71
+ ]);
72
+ /** Approved (`stage 1`) without `stage 2`: undo (legacy `CONFIRMATION_TIMEOUT_MS`). */
73
+ const CLISITEF_CONFIRMATION_TIMEOUT_MS = 6e4;
74
+ /** Legacy operator when the merchant config has none. */
75
+ const CLISITEF_DEFAULT_OPERATOR = "KIOSKO_BR";
76
+ /** Device-wide record of the last transaction, to undo it after a crash. */
77
+ const CLISITEF_STORAGE_KEY = "clisitef:transaction:v1";
78
+ //#endregion
79
+ //#region src/errors.ts
80
+ const source = "docs/payments/clisitef/pinpad.md#11-errores";
81
+ const entry = (code, extra = {}) => {
82
+ return {
83
+ code,
84
+ source,
85
+ ...extra
86
+ };
87
+ };
88
+ const invalid = (message) => entry("INVALID_REQUEST", { message });
89
+ /**
90
+ * Ficha §11 (Fiserv "Tabela de códigos de retorno"); other positive codes
91
+ * (authorizer) fall back to `CARD_DECLINED`, other negatives to `UNKNOWN`.
92
+ */
93
+ const clisitefPinPadErrors = definePaymentErrors({
94
+ "-1": entry("TERMINAL_NEEDS_INIT", { retryable: true }),
95
+ "-2": entry("CANCELLED_BY_USER"),
96
+ "-3": invalid("Invalid CliSiTef function or modality"),
97
+ "-4": entry("TERMINAL_UNAVAILABLE", { message: "Out of memory" }),
98
+ "-5": entry("PROVIDER_UNAVAILABLE"),
99
+ "-6": entry("CANCELLED_BY_USER"),
100
+ "-8": entry("TERMINAL_NEEDS_INIT", { message: "CliSiTef outdated" }),
101
+ "-9": invalid("CliSiTef iterative flow not started"),
102
+ "-10": invalid("Missing mandatory CliSiTef parameter"),
103
+ "-12": entry("TERMINAL_BUSY"),
104
+ "-13": entry("UNKNOWN", { message: "Fiscal document not found" }),
105
+ "-15": entry("CANCELLED_BY_USER"),
106
+ "-20": invalid("Invalid CliSiTef parameter"),
107
+ "-21": invalid("Prohibited word in pinpad collection"),
108
+ "-24": invalid("Digital wallet not enabled"),
109
+ "-30": entry("TERMINAL_UNAVAILABLE", { message: "File access error" }),
110
+ "-40": entry("CARD_DECLINED", { message: "Declined by the SiTef server" }),
111
+ "-41": invalid("Invalid data"),
112
+ "-43": entry("TERMINAL_UNAVAILABLE", { message: "Pinpad routine failed" }),
113
+ "-50": entry("FRAUD_SUSPECTED", { message: "Unsecured transaction" }),
114
+ "-100": entry("UNKNOWN", { message: "CliSiTef internal error" }),
115
+ [CLISITEF_TIMEOUT_CODE]: entry("TIMEOUT")
116
+ });
117
+ //#endregion
118
+ //#region src/metadata.ts
119
+ const MASKED_PAN = /\d{0,6}[*Xx]{4,}\s*(\d{4})(?!\d)/;
120
+ const field = (fields, id) => {
121
+ const value = fields.get(id)?.trim();
122
+ return value ? value : null;
123
+ };
124
+ /** Last 4 digits of the masked PAN printed on the receipt. */
125
+ const clisitefLast4 = (receipt) => {
126
+ if (!receipt) return null;
127
+ return MASKED_PAN.exec(receipt)?.[1] ?? null;
128
+ };
129
+ /**
130
+ * Field 132. Fiserv documents it as "a table to be provided"; these codes
131
+ * come from the legacy production catalog (ficha §8).
132
+ */
133
+ const BRANDS = {
134
+ "00001": "VISA",
135
+ "00002": "MASTERCARD",
136
+ "00004": "AMEX",
137
+ "00011": "JCB",
138
+ "10014": "DISCOVER",
139
+ "20001": "MAESTRO",
140
+ "20002": "VISA_ELECTRON",
141
+ "20137": "TELENET"
142
+ };
143
+ /** Field 2090 (Fiserv "Tabela TipoCampo"). */
144
+ const ENTRY_MODES = {
145
+ "00": "SWIPE",
146
+ "03": "CHIP",
147
+ "05": "CONTACTLESS",
148
+ "06": "CONTACTLESS",
149
+ "99": "MANUAL"
150
+ };
151
+ const clisitefBrand = (fields) => {
152
+ const code = field(fields, CLISITEF_FIELD.CARD_TYPE_CODE);
153
+ if (!code || code === "00000") return null;
154
+ return BRANDS[code] ?? code;
155
+ };
156
+ const CARD_TYPES = {
157
+ DEBIT: "DEBIT",
158
+ CREDIT: "CREDIT",
159
+ VOUCHER: "PREPAID",
160
+ PIX: null
161
+ };
162
+ const clisitefMetadata = (input) => {
163
+ const { fields } = input;
164
+ const customer = field(fields, CLISITEF_FIELD.CUSTOMER_RECEIPT);
165
+ const merchant = field(fields, CLISITEF_FIELD.MERCHANT_RECEIPT);
166
+ const brand = clisitefBrand(fields);
167
+ const last4 = field(fields, CLISITEF_FIELD.LAST4)?.slice(-4) ?? null;
168
+ const entry = field(fields, CLISITEF_FIELD.ENTRY_MODE);
169
+ const institution = field(fields, CLISITEF_FIELD.INSTITUTION_NAME);
170
+ const p1 = {
171
+ provider_transaction_id: field(fields, CLISITEF_FIELD.SITEF_NSU),
172
+ authorization_code: field(fields, CLISITEF_FIELD.AUTHORIZATION_CODE),
173
+ reference: field(fields, CLISITEF_FIELD.HOST_NSU)
174
+ };
175
+ const p2 = {
176
+ card_type: CARD_TYPES[input.modality] ?? null,
177
+ brand
178
+ };
179
+ const p3 = {
180
+ last4: last4 ?? clisitefLast4(customer ?? merchant),
181
+ entry_mode: entry ? ENTRY_MODES[entry] ?? null : null
182
+ };
183
+ const p4 = { acquirer: institution ?? field(fields, CLISITEF_FIELD.INSTITUTION_CODE) };
184
+ const p5 = { terminal_id: input.terminalNumber };
185
+ const p6 = { ticket_number: input.fiscalCoupon };
186
+ const p7 = { transaction_date: input.fiscalDate };
187
+ const payment = {
188
+ ...p1,
189
+ ...p2,
190
+ ...p3,
191
+ ...p4,
192
+ ...p5,
193
+ ...p6,
194
+ ...p7
195
+ };
196
+ const receipt = customer !== null || merchant !== null ? {
197
+ customer,
198
+ merchant,
199
+ format: "text"
200
+ } : void 0;
201
+ return {
202
+ attempt_reference: input.attemptReference,
203
+ payment,
204
+ receipt
205
+ };
206
+ };
207
+ /** PIN_PAD tender details; `null` without brand and last 4 (schema minimum). */
208
+ const clisitefDetails = (metadata) => {
209
+ const payment = metadata.payment;
210
+ const brand = payment?.brand?.slice(0, 32);
211
+ const last4 = payment?.last4;
212
+ const terminal = payment?.terminal_id;
213
+ if (!brand || !last4 || !terminal) return null;
214
+ return {
215
+ method: "PIN_PAD",
216
+ brand,
217
+ last4,
218
+ auth_code: payment.authorization_code ?? void 0,
219
+ terminal_id: terminal
220
+ };
221
+ };
222
+ //#endregion
223
+ //#region src/settings.ts
224
+ const CLISITEF_PINPAD_TYPES = [
225
+ "ANDROID_USB",
226
+ "ANDROID_BT",
227
+ "ANDROID_AUTO"
228
+ ];
229
+ /** Ficha §6: filled per kiosk in the device settings. */
230
+ const clisitefPinPadDeviceFields = [
231
+ {
232
+ key: "sitef_ip",
233
+ label: "SiTef server IP",
234
+ type: "text",
235
+ required: true
236
+ },
237
+ {
238
+ key: "store_code",
239
+ label: "SiTef store code",
240
+ type: "text",
241
+ required: true
242
+ },
243
+ {
244
+ key: "terminal_number",
245
+ label: "SiTef terminal number",
246
+ type: "text",
247
+ required: true
248
+ },
249
+ {
250
+ key: "cnpj_store",
251
+ label: "Store CNPJ",
252
+ type: "text",
253
+ required: true
254
+ },
255
+ {
256
+ key: "pinpad_type",
257
+ label: "Pinpad connection",
258
+ type: "select",
259
+ required: true,
260
+ options: [...CLISITEF_PINPAD_TYPES]
261
+ }
262
+ ];
263
+ const text = (value) => {
264
+ return typeof value === "string" ? value.trim() : "";
265
+ };
266
+ const notConfigured = (missing) => {
267
+ return new PaymentError(createPaymentError("TERMINAL_NOT_CONFIGURED", { message: `CliSiTef is missing ${missing.join(", ")}` }));
268
+ };
269
+ const isModality = (value) => {
270
+ return value === "DEBIT" || value === "CREDIT" || value === "VOUCHER";
271
+ };
272
+ /** `payments.config` (merchant) + device settings; throws when incomplete. */
273
+ const readClisitefPinPadSettings = (config, device) => {
274
+ const modality = text(config.modality);
275
+ const cnpjEnterprise = text(config.cnpj_enterprise);
276
+ const serverIp = text(device.sitef_ip);
277
+ const storeCode = text(device.store_code);
278
+ const terminalNumber = text(device.terminal_number);
279
+ const cnpjStore = text(device.cnpj_store).replace(/\D/g, "");
280
+ const pinpadType = text(device.pinpad_type) || void 0;
281
+ const required = {
282
+ modality,
283
+ cnpj_enterprise: cnpjEnterprise
284
+ };
285
+ const fromDevice = {
286
+ sitef_ip: serverIp,
287
+ store_code: storeCode
288
+ };
289
+ const more = {
290
+ terminal_number: terminalNumber,
291
+ cnpj_store: cnpjStore
292
+ };
293
+ const values = {
294
+ ...required,
295
+ ...fromDevice
296
+ };
297
+ Object.assign(values, more);
298
+ const missing = Object.keys(values).filter((key) => !values[key]);
299
+ if (missing.length) throw notConfigured(missing);
300
+ if (!isModality(modality)) throw notConfigured(["a valid modality"]);
301
+ return {
302
+ configure: {
303
+ serverIp,
304
+ storeCode,
305
+ terminalNumber,
306
+ additionalParams: clisitefAdditionalParams({
307
+ cnpjStore,
308
+ cnpjEnterprise,
309
+ pinpadType
310
+ })
311
+ },
312
+ modality,
313
+ operator: text(config.operator) || "KIOSKO_BR",
314
+ restrictions: text(config.restrictions),
315
+ terminalNumber
316
+ };
317
+ };
318
+ //#endregion
319
+ //#region src/store.ts
320
+ const isRecord = (value) => {
321
+ if (!value || typeof value !== "object") return false;
322
+ const record = value;
323
+ return typeof record.fiscalCoupon === "string" && typeof record.attemptReference === "string";
324
+ };
325
+ const readTransaction = async (storage) => {
326
+ const raw = await storage.get(CLISITEF_STORAGE_KEY);
327
+ if (!raw) return null;
328
+ try {
329
+ const parsed = JSON.parse(raw);
330
+ return isRecord(parsed) ? parsed : null;
331
+ } catch {
332
+ return null;
333
+ }
334
+ };
335
+ const writeTransaction = async (storage, record) => {
336
+ await storage.set(CLISITEF_STORAGE_KEY, JSON.stringify(record));
337
+ };
338
+ const isOpen = (record) => {
339
+ return record.state === "started" || record.state === "approved";
340
+ };
341
+ //#endregion
342
+ //#region src/transaction.ts
343
+ const errorCode = (error) => {
344
+ if (!error || typeof error !== "object") return null;
345
+ const code = error.code;
346
+ return typeof code === "string" || typeof code === "number" ? code : null;
347
+ };
348
+ const errorMessage = (error) => {
349
+ return error instanceof Error ? error.message : null;
350
+ };
351
+ const inputType = (command) => {
352
+ if (command === CLISITEF_COMMAND.READ_MASKED) return "password";
353
+ if (command === CLISITEF_COMMAND.READ_AMOUNT) return "number";
354
+ return "text";
355
+ };
356
+ const MESSAGES = /* @__PURE__ */ new Set([
357
+ CLISITEF_COMMAND.MESSAGE_OPERATOR,
358
+ CLISITEF_COMMAND.MESSAGE_CUSTOMER,
359
+ CLISITEF_COMMAND.MESSAGE_BOTH,
360
+ CLISITEF_COMMAND.PRESS_KEY,
361
+ CLISITEF_COMMAND.FOOTER
362
+ ]);
363
+ const SILENT = /* @__PURE__ */ new Set([
364
+ CLISITEF_COMMAND.CLEAR_OPERATOR,
365
+ CLISITEF_COMMAND.CLEAR_CUSTOMER,
366
+ CLISITEF_COMMAND.CLEAR_BOTH,
367
+ CLISITEF_COMMAND.HEADER,
368
+ CLISITEF_COMMAND.CLEAR_HEADER,
369
+ CLISITEF_COMMAND.CHECK_ABORT
370
+ ]);
371
+ const READS = /* @__PURE__ */ new Set([
372
+ CLISITEF_COMMAND.READ_FIELD,
373
+ CLISITEF_COMMAND.READ_AMOUNT,
374
+ CLISITEF_COMMAND.READ_MASKED
375
+ ]);
376
+ /**
377
+ * One CliSiTef transaction: `startTransaction`, the `onData` loop answered
378
+ * through `ui`, `finishTransaction(1)` on approval (`stage 1` = 0) and
379
+ * success only when `stage 2` closes with 0. Never rejects.
380
+ */
381
+ const runClisitefTransaction = (input) => {
382
+ const { client, ui, signal } = input;
383
+ const fields = /* @__PURE__ */ new Map();
384
+ const subscriptions = [];
385
+ let title = "";
386
+ let captured = false;
387
+ let approved = false;
388
+ let closing = false;
389
+ let aborted = false;
390
+ let watchdog;
391
+ let queue = Promise.resolve();
392
+ let resolve = () => void 0;
393
+ const done = new Promise((r) => resolve = r);
394
+ const settle = (status, reason) => {
395
+ clearTimeout(watchdog);
396
+ for (const subscription of subscriptions) subscription.remove();
397
+ signal.removeEventListener("abort", onAbort);
398
+ resolve({
399
+ status,
400
+ ...reason,
401
+ fields,
402
+ aborted
403
+ });
404
+ };
405
+ const undo = async (reason) => {
406
+ try {
407
+ const p1 = {
408
+ confirm: CLISITEF_CONFIRM.UNDO,
409
+ ...input.finish
410
+ };
411
+ await client.finishTransaction(p1);
412
+ settle("undone", reason);
413
+ } catch (error) {
414
+ settle("unresolved", {
415
+ ...reason,
416
+ message: errorMessage(error)
417
+ });
418
+ }
419
+ };
420
+ const close = async (reason) => {
421
+ if (closing) return;
422
+ closing = true;
423
+ if (!approved) await client.abortTransaction(CLISITEF_ABORT_FLAG).catch(() => 0);
424
+ if (captured || approved) return undo(reason);
425
+ settle("declined", reason);
426
+ };
427
+ function onAbort() {
428
+ aborted = true;
429
+ close({
430
+ code: null,
431
+ message: "Aborted by the payment deadline"
432
+ });
433
+ }
434
+ const reply = async (data) => {
435
+ if (closing) return;
436
+ await client.continueTransaction(data);
437
+ };
438
+ const onData = async (event) => {
439
+ const { command, input: text } = event;
440
+ if (command === CLISITEF_COMMAND.STORE_FIELD) {
441
+ fields.set(event.fieldId, text);
442
+ if (CLISITEF_CAPTURE_FIELDS.has(event.fieldId)) captured = true;
443
+ return reply("");
444
+ }
445
+ if (MESSAGES.has(command)) {
446
+ if (text.trim()) ui.message({
447
+ text: text.trim(),
448
+ kind: "waiting"
449
+ });
450
+ return reply("");
451
+ }
452
+ if (command === CLISITEF_COMMAND.MENU_TITLE) {
453
+ title = text.trim();
454
+ return reply("");
455
+ }
456
+ if (command === CLISITEF_COMMAND.CLEAR_MENU_TITLE) {
457
+ title = "";
458
+ return reply("");
459
+ }
460
+ if (SILENT.has(command)) return reply("");
461
+ if (command === CLISITEF_COMMAND.CONFIRM) {
462
+ const yes = await ui.confirm({ text: text.trim() || title });
463
+ return reply(yes ? "0" : "1");
464
+ }
465
+ if (command === CLISITEF_COMMAND.MENU) {
466
+ const options = parseClisitefMenu(text);
467
+ const label = title || "Selecione uma opção";
468
+ return reply(await ui.select({
469
+ title: label,
470
+ options
471
+ }));
472
+ }
473
+ if (READS.has(command)) {
474
+ const label = text.trim() || title || "Informe o dado";
475
+ const max = event.maxLength > 0 ? event.maxLength : void 0;
476
+ const p1 = {
477
+ label,
478
+ type: inputType(command),
479
+ maxLength: max
480
+ };
481
+ return reply(await ui.input(p1));
482
+ }
483
+ const message = `Unsupported CliSiTef command ${command}`;
484
+ return close({
485
+ code: `UNSUPPORTED_COMMAND_${command}`,
486
+ message
487
+ });
488
+ };
489
+ const confirm = () => {
490
+ const message = "CliSiTef did not close the confirmation";
491
+ const expire = () => {
492
+ if (closing) return;
493
+ closing = true;
494
+ undo({
495
+ code: null,
496
+ message
497
+ });
498
+ };
499
+ watchdog = setTimeout(expire, input.confirmationTimeoutMs);
500
+ const p1 = {
501
+ confirm: CLISITEF_CONFIRM.CONFIRM,
502
+ ...input.finish
503
+ };
504
+ client.finishTransaction(p1).catch((error) => {
505
+ if (closing) return;
506
+ closing = true;
507
+ clearTimeout(watchdog);
508
+ undo({
509
+ code: errorCode(error),
510
+ message: errorMessage(error)
511
+ });
512
+ });
513
+ };
514
+ const onResult = async (event) => {
515
+ const { stage, resultCode: code } = event;
516
+ if (closing) return;
517
+ if (stage === 1 && code === CLISITEF_RESULT.OK) {
518
+ approved = true;
519
+ await input.onApproved(fields);
520
+ if (!closing) confirm();
521
+ return;
522
+ }
523
+ if (stage === 1) {
524
+ closing = true;
525
+ if (!(captured && CLISITEF_INCONCLUSIVE_CODES.has(code))) return settle("declined", {
526
+ code,
527
+ message: null
528
+ });
529
+ await client.abortTransaction(CLISITEF_ABORT_FLAG).catch(() => 0);
530
+ return undo({
531
+ code,
532
+ message: null
533
+ });
534
+ }
535
+ if (!approved) return;
536
+ closing = true;
537
+ if (code === CLISITEF_RESULT.OK) return settle("confirmed", {
538
+ code,
539
+ message: null
540
+ });
541
+ return undo({
542
+ code,
543
+ message: null
544
+ });
545
+ };
546
+ const enqueue = (handle) => {
547
+ const run = async () => {
548
+ await handle();
549
+ };
550
+ queue = queue.then(run).catch(async (error) => {
551
+ const reason = {
552
+ code: errorCode(error),
553
+ message: errorMessage(error)
554
+ };
555
+ if (closing) return;
556
+ await close({
557
+ ...reason,
558
+ error
559
+ });
560
+ });
561
+ };
562
+ const begin = async () => {
563
+ if (signal.aborted) {
564
+ aborted = true;
565
+ return settle("declined", {
566
+ code: null,
567
+ message: "Aborted"
568
+ });
569
+ }
570
+ signal.addEventListener("abort", onAbort);
571
+ const handleData = (e) => enqueue(() => onData(e));
572
+ const handleResult = (e) => {
573
+ enqueue(() => onResult(e));
574
+ };
575
+ subscriptions.push(client.onData(handleData));
576
+ subscriptions.push(client.onTransactionResult(handleResult));
577
+ try {
578
+ const code = await client.startTransaction(input.start);
579
+ if (code === CLISITEF_RESULT.CONTINUE || closing) return;
580
+ closing = true;
581
+ settle("declined", {
582
+ code,
583
+ message: null
584
+ });
585
+ } catch (error) {
586
+ if (closing) return;
587
+ closing = true;
588
+ const reason = {
589
+ code: errorCode(error),
590
+ message: errorMessage(error)
591
+ };
592
+ settle("declined", reason);
593
+ }
594
+ };
595
+ begin();
596
+ return done;
597
+ };
598
+ //#endregion
599
+ //#region src/adapter.ts
600
+ /** Confirmed in the act (`finishTransaction(1)`), never captured later. */
601
+ const clisitefPinPadCapabilities = {
602
+ deferredCapture: false,
603
+ inPerson: true
604
+ };
605
+ const createLock = () => {
606
+ let tail = Promise.resolve();
607
+ return (task) => {
608
+ const run = tail.then(task, task);
609
+ tail = run.catch(() => void 0);
610
+ return run;
611
+ };
612
+ };
613
+ const failed = (record, reference, error, needsReview = false) => {
614
+ const base = record.metadata ?? { attempt_reference: reference };
615
+ const review = needsReview ? { needs_review: true } : {};
616
+ const metadata = {
617
+ ...base,
618
+ attempt_reference: reference,
619
+ error,
620
+ ...review
621
+ };
622
+ return {
623
+ status: "FAILED",
624
+ amount: record.amount,
625
+ metadata,
626
+ error
627
+ };
628
+ };
629
+ const paid = (record) => {
630
+ const reference = record.attemptReference;
631
+ const metadata = record.metadata ?? { attempt_reference: reference };
632
+ const details = record.details ?? null;
633
+ return {
634
+ status: "PAID",
635
+ amount: record.amount,
636
+ metadata,
637
+ details
638
+ };
639
+ };
640
+ const outcomeError = (outcome, attempt) => {
641
+ const provider = {
642
+ provider_message: outcome.message,
643
+ attempt
644
+ };
645
+ const code = outcome.code == null ? null : String(outcome.code);
646
+ const extra = {
647
+ ...provider,
648
+ provider_code: code
649
+ };
650
+ if (outcome.aborted) return createPaymentError("TIMEOUT", extra);
651
+ if (outcome.status === "unresolved") return createPaymentError("AMBIGUOUS", extra);
652
+ if (outcome.code === null) {
653
+ const message = outcome.message ?? void 0;
654
+ return createPaymentError("PROVIDER_UNAVAILABLE", {
655
+ ...extra,
656
+ retryable: false,
657
+ message
658
+ });
659
+ }
660
+ const fallback = typeof outcome.code === "number" && outcome.code > 0 ? "CARD_DECLINED" : "UNKNOWN";
661
+ return toPaymentError(clisitefPinPadErrors, {
662
+ code: outcome.code,
663
+ message: outcome.message,
664
+ attempt,
665
+ fallback
666
+ });
667
+ };
668
+ const terminalError = (error) => {
669
+ const message = error instanceof Error ? error.message : String(error);
670
+ return {
671
+ ok: false,
672
+ message,
673
+ error: createPaymentError("TERMINAL_UNAVAILABLE", { message })
674
+ };
675
+ };
676
+ /**
677
+ * CliSiTef (Software Express) on the kiosk pinpad, Brazil. One adapter per
678
+ * modality payment (DEBIT / CREDIT / VOUCHER in `payments.config`). The
679
+ * pinpad waits on the customer: give the payment a `runtime.timeout_ms`
680
+ * well above the 30 s default (e.g. 90 000).
681
+ */
682
+ const clisitefPinPadPayments = (options = {}) => {
683
+ const client = options.client ?? clisitef;
684
+ const now = options.now ?? (() => /* @__PURE__ */ new Date());
685
+ const confirmationMs = options.confirmationTimeoutMs ?? 6e4;
686
+ const lock = createLock();
687
+ const storageOf = (ctx) => {
688
+ return options.storage ?? ctx.storage;
689
+ };
690
+ const configure = async (settings) => {
691
+ const code = await client.configure(settings.configure);
692
+ if (code === 0) return null;
693
+ client.invalidate();
694
+ return toPaymentError(clisitefPinPadErrors, {
695
+ code,
696
+ fallback: "TERMINAL_NOT_CONFIGURED"
697
+ });
698
+ };
699
+ /** Undoes a transaction a crash or a lost result left open. */
700
+ const recover = async (storage, record) => {
701
+ const { fiscalCoupon, fiscalDate, time } = record;
702
+ const count = client.getQttPendingTransactions;
703
+ const pending = await count(fiscalDate, fiscalCoupon).catch(() => null);
704
+ if (pending === null) return record;
705
+ let next;
706
+ if (pending > 0) {
707
+ const p1 = {
708
+ confirm: CLISITEF_CONFIRM.UNDO,
709
+ fiscalCoupon,
710
+ fiscalDate
711
+ };
712
+ if (await client.finishTransaction({
713
+ ...p1,
714
+ time
715
+ }).catch(() => -1) !== 0) return record;
716
+ const error = createPaymentError("PROVIDER_UNAVAILABLE", {
717
+ retryable: false,
718
+ message: "Pending CliSiTef transaction undone"
719
+ });
720
+ next = {
721
+ ...record,
722
+ state: "undone",
723
+ error
724
+ };
725
+ } else if (record.state === "approved") {
726
+ const error = createPaymentError("AMBIGUOUS");
727
+ next = {
728
+ ...record,
729
+ state: "review",
730
+ error
731
+ };
732
+ } else {
733
+ const error = createPaymentError("PROVIDER_UNAVAILABLE", {
734
+ retryable: false,
735
+ message: "CliSiTef transaction never approved"
736
+ });
737
+ next = {
738
+ ...record,
739
+ state: "undone",
740
+ error
741
+ };
742
+ }
743
+ await writeTransaction(storage, next);
744
+ return next;
745
+ };
746
+ /** Configures and resolves the open record of the device, if any. */
747
+ const prepare = async (ctx) => {
748
+ const settings = readClisitefPinPadSettings(ctx.config, ctx.deviceSettings);
749
+ const error = await configure(settings);
750
+ const storage = storageOf(ctx);
751
+ let record = await readTransaction(storage);
752
+ if (!error && record && isOpen(record)) record = await recover(storage, record);
753
+ return {
754
+ settings,
755
+ error,
756
+ storage,
757
+ record
758
+ };
759
+ };
760
+ const fromRecord = (record, ctx) => {
761
+ const reference = ctx.attemptReference;
762
+ if (record.state === "confirmed") return paid(record);
763
+ if (record.state === "review") {
764
+ const error = record.error ?? createPaymentError("AMBIGUOUS");
765
+ return failed(record, reference, error, true);
766
+ }
767
+ if (record.state === "undone") {
768
+ const fallback = createPaymentError("UNKNOWN", { retryable: false });
769
+ return failed(record, reference, record.error ?? fallback);
770
+ }
771
+ const error = createPaymentError("TIMEOUT", { attempt: ctx.attempt });
772
+ return failed(record, reference, error);
773
+ };
774
+ const charge = async (ctx) => {
775
+ const amount = ctx.amount.value;
776
+ const reference = ctx.attemptReference;
777
+ const empty = { amount };
778
+ if (!client.available) {
779
+ const error = createPaymentError("TERMINAL_UNAVAILABLE");
780
+ return failed(empty, reference, error);
781
+ }
782
+ const prepared = await prepare(ctx);
783
+ const { settings, storage, record: previous } = prepared;
784
+ if (prepared.error) return failed(empty, reference, prepared.error);
785
+ if (previous?.attemptReference === reference && previous?.state === "confirmed") return paid(previous);
786
+ if (previous && isOpen(previous)) {
787
+ const error = createPaymentError("TERMINAL_BUSY", { attempt: ctx.attempt });
788
+ return failed(empty, reference, error);
789
+ }
790
+ const date = now();
791
+ const fiscal = clisitefFiscalDateTime(date, options.timeZone);
792
+ const fiscalCoupon = String(date.getTime());
793
+ const finish = {
794
+ fiscalCoupon,
795
+ ...fiscal
796
+ };
797
+ const record = {
798
+ attemptReference: reference,
799
+ ...finish,
800
+ amount,
801
+ startedAt: date.getTime(),
802
+ state: "started"
803
+ };
804
+ await writeTransaction(storage, record);
805
+ const s1 = {
806
+ modality: CLISITEF_MODALITY[settings.modality],
807
+ value: formatClisitefAmount(amount),
808
+ ...finish
809
+ };
810
+ const s2 = { operator: settings.operator };
811
+ const start = {
812
+ ...s1,
813
+ ...s2,
814
+ restrictions: settings.restrictions
815
+ };
816
+ const meta = {
817
+ modality: settings.modality,
818
+ fiscalCoupon
819
+ };
820
+ const m1 = {
821
+ terminalNumber: settings.terminalNumber,
822
+ ...meta
823
+ };
824
+ const metadataOf = (fields) => {
825
+ const m2 = {
826
+ attemptReference: reference,
827
+ fields
828
+ };
829
+ return clisitefMetadata({
830
+ ...m1,
831
+ ...m2,
832
+ fiscalDate: fiscal.fiscalDate
833
+ });
834
+ };
835
+ const onApproved = async (fields) => {
836
+ const metadata = metadataOf(fields);
837
+ await writeTransaction(storage, {
838
+ ...record,
839
+ state: "approved",
840
+ metadata
841
+ });
842
+ };
843
+ const t1 = {
844
+ client,
845
+ ui: ctx.ui,
846
+ signal: ctx.signal,
847
+ start,
848
+ finish
849
+ };
850
+ const t2 = {
851
+ confirmationTimeoutMs: confirmationMs,
852
+ onApproved
853
+ };
854
+ const outcome = await runClisitefTransaction({
855
+ ...t1,
856
+ ...t2
857
+ });
858
+ const metadata = metadataOf(outcome.fields);
859
+ if (outcome.status === "confirmed") {
860
+ const details = clisitefDetails(metadata);
861
+ const confirmed = {
862
+ ...record,
863
+ metadata,
864
+ details,
865
+ state: "confirmed"
866
+ };
867
+ await writeTransaction(storage, confirmed);
868
+ return paid(confirmed);
869
+ }
870
+ if (outcome.code === -1) client.invalidate();
871
+ const error = outcomeError(outcome, ctx.attempt);
872
+ const unresolved = outcome.status === "unresolved";
873
+ const state = unresolved ? "approved" : "undone";
874
+ const closed = {
875
+ ...record,
876
+ state,
877
+ metadata,
878
+ error
879
+ };
880
+ await writeTransaction(storage, closed);
881
+ if (outcome.error) throw outcome.error;
882
+ return failed(closed, reference, error, unresolved);
883
+ };
884
+ const query = async (ctx, result) => {
885
+ const reference = result.metadata.attempt_reference;
886
+ const scoped = {
887
+ ...ctx,
888
+ attemptReference: reference
889
+ };
890
+ const { record, error } = await prepare(scoped);
891
+ if (record?.attemptReference !== reference) {
892
+ const missing = createPaymentError("UNKNOWN", {
893
+ retryable: false,
894
+ message: "No CliSiTef transaction for this attempt"
895
+ });
896
+ return failed(result, reference, missing);
897
+ }
898
+ if (error && isOpen(record)) return failed(record, reference, error);
899
+ return fromRecord(record, scoped);
900
+ };
901
+ const cancel = async (ctx, result) => {
902
+ const next = await query(ctx, result);
903
+ if (next.status === "PAID") {
904
+ const error = createPaymentError("REVERSAL_NOT_ALLOWED");
905
+ return {
906
+ ...next,
907
+ status: "FAILED",
908
+ error
909
+ };
910
+ }
911
+ const code = next.error?.code;
912
+ if (!(code !== "AMBIGUOUS" && code !== "TIMEOUT")) return next;
913
+ return {
914
+ ...next,
915
+ status: "CANCELLED",
916
+ error: void 0
917
+ };
918
+ };
919
+ const operation = (run) => {
920
+ return (ctx) => {
921
+ const task = async () => {
922
+ try {
923
+ const data = await run(ctx);
924
+ return {
925
+ ok: true,
926
+ message: typeof data === "string" ? data : null,
927
+ data: data && typeof data === "object" ? data : void 0
928
+ };
929
+ } catch (error) {
930
+ return terminalError(error);
931
+ }
932
+ };
933
+ return lock(task);
934
+ };
935
+ };
936
+ const terminal = {
937
+ init: operation(async (ctx) => {
938
+ client.invalidate();
939
+ const s1 = readClisitefPinPadSettings(ctx.config, ctx.deviceSettings);
940
+ const error = await configure(s1);
941
+ if (error) throw new Error(error.message);
942
+ return "CliSiTef configured";
943
+ }),
944
+ test: operation(async () => `CliSiTef ${await client.getVersion()}`),
945
+ status: operation(async () => client.getHealth() ?? {}),
946
+ extra: [{
947
+ key: "submit_pending_messages",
948
+ label: "Send pending messages",
949
+ run: operation(async () => {
950
+ return `Pending messages sent (${await client.submitPendingMessages()})`;
951
+ })
952
+ }, {
953
+ key: "release_pinpad",
954
+ label: "Release pinpad",
955
+ run: operation(async () => {
956
+ await client.closePinPad();
957
+ await client.disconnectSitef();
958
+ client.invalidate();
959
+ return "Pinpad released";
960
+ })
961
+ }]
962
+ };
963
+ return {
964
+ provider: "clisitef",
965
+ method: "PIN_PAD",
966
+ deviceFields: clisitefPinPadDeviceFields,
967
+ errors: clisitefPinPadErrors,
968
+ capabilities: clisitefPinPadCapabilities,
969
+ start: (ctx) => lock(() => charge(ctx)),
970
+ query: (ctx, result) => lock(() => query(ctx, result)),
971
+ cancel: (ctx, result) => lock(() => cancel(ctx, result)),
972
+ reversalFor: (result) => result.status === "PAID" ? "manual" : "cancel",
973
+ terminal
974
+ };
975
+ };
976
+ //#endregion
977
+ export { CLISITEF_CANCEL_CODES, CLISITEF_CAPTURE_FIELDS, CLISITEF_COMMAND, CLISITEF_CONFIRMATION_TIMEOUT_MS, CLISITEF_DEFAULT_OPERATOR, CLISITEF_FIELD, CLISITEF_INCONCLUSIVE_CODES, CLISITEF_NO, CLISITEF_PINPAD_TYPES, CLISITEF_STORAGE_KEY, CLISITEF_YES, clisitefDetails, clisitefLast4, clisitefMetadata, clisitefPinPadCapabilities, clisitefPinPadDeviceFields, clisitefPinPadErrors, clisitefPinPadPayments, isOpen, readClisitefPinPadSettings, readTransaction, runClisitefTransaction, writeTransaction };
package/package.json CHANGED
@@ -1,6 +1,61 @@
1
1
  {
2
2
  "name": "@fire-spark/payments-clisitef-pinpad-rn",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.7.0",
4
+ "description": "Fire Spark CliSiTef (Software Express) pinpad adapter for Brazil: debit, credit and voucher on Android kiosks",
5
+ "type": "module",
6
+ "sideEffects": false,
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "main": "./dist/index.js",
11
+ "types": "./dist/index.d.ts",
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/index.js",
16
+ "default": "./dist/index.js"
17
+ }
18
+ },
19
+ "dependencies": {
20
+ "@fire-spark/payments": "^0.7.0",
21
+ "@fire-spark/payments-clisitef-client": "^0.7.0",
22
+ "@fire-spark/types": "^0.7.0"
23
+ },
24
+ "devDependencies": {
25
+ "tsdown": "^0.22.14",
26
+ "typescript": "^7.0.2",
27
+ "vitest": "^2.1.8"
28
+ },
29
+ "publishConfig": {
30
+ "access": "public"
31
+ },
32
+ "tsdown": {
33
+ "entry": [
34
+ "src/index.ts"
35
+ ],
36
+ "format": [
37
+ "esm"
38
+ ],
39
+ "platform": "neutral",
40
+ "dts": {
41
+ "tsconfig": "tsconfig.build.json"
42
+ },
43
+ "clean": true,
44
+ "deps": {
45
+ "neverBundle": [
46
+ "@fire-spark/payments",
47
+ "@fire-spark/payments-clisitef-client",
48
+ "@fire-spark/types"
49
+ ]
50
+ }
51
+ },
52
+ "scripts": {
53
+ "build": "tsdown",
54
+ "dev": "tsdown --watch",
55
+ "check-types": "tsc --noEmit",
56
+ "test:utils": "vitest run",
57
+ "lint": "oxlint ./src --max-warnings=0",
58
+ "format": "oxfmt ./src",
59
+ "check-format": "oxfmt --check ./src"
60
+ }
6
61
  }
package/README.md DELETED
@@ -1,3 +0,0 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.