@fire-spark/payments-deuna-widget 0.12.0 → 0.12.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.
package/dist/index.d.ts CHANGED
@@ -99,9 +99,10 @@ type DeunaWidgetOutcome =
99
99
  by: "user" | "system";
100
100
  };
101
101
  /**
102
- * Implemented once per template with the DEUNA SDK
103
- * (`@deuna/react-native-sdk` or the Web SDK). It opens the widget with the
104
- * given order token and resolves with the first final callback.
102
+ * Implemented once per template with the DEUNA Web SDK (in the page, or in
103
+ * a `react-native-webview` on React Native) or `@deuna/react-native-sdk`.
104
+ * It opens the widget with the given order token and resolves with the
105
+ * first final callback.
105
106
  */
106
107
  type DeunaWidgetBridge = {
107
108
  open(input: DeunaWidgetOpenInput): Promise<DeunaWidgetOutcome>;
@@ -126,6 +127,8 @@ type DeunaOrderState = {
126
127
  order_token: string;
127
128
  status: DeunaPaymentStatus | (string & {});
128
129
  transaction_id?: string | null;
130
+ /** Processor DEUNA charged with (`payment.data.processor`), if reported. */
131
+ processor?: string | null;
129
132
  /** DEUNA `error.code` (core, `DP-`, `EMA-`…) when the payment failed. */
130
133
  error?: {
131
134
  code: string | null;
@@ -160,10 +163,27 @@ type DeunaWidgetOptions = {
160
163
  };
161
164
  /** Processors this method can charge with. */
162
165
  declare const deunaProcessorsFor: (method: DeunaWidgetMethod) => ("card" | "daviplata" | "deuna_wallet" | "mercadopago" | "nequi" | "pse")[];
163
- /** `payments.config.processor`; optional when the method has only one. */
166
+ /**
167
+ * Processors one charge opens the widget with. `config.processors` lists
168
+ * the processors the payment enables (same DEUNA credentials); a channel
169
+ * that shows one option per processor sets the customer's pick in
170
+ * `config.processor`, which wins: the widget opens only that one. Without
171
+ * a pick every enabled processor is offered and the customer chooses in
172
+ * the widget. A legacy payment has only `config.processor`; it is
173
+ * optional when the method has one processor. Kept in `DEUNA_PROCESSORS`
174
+ * order.
175
+ */
176
+ declare const resolveDeunaProcessors: (method: DeunaWidgetMethod, config: Record<string, unknown>) => DeunaProcessor[];
177
+ /** @deprecated Use `resolveDeunaProcessors`: first configured processor. */
164
178
  declare const resolveDeunaProcessor: (method: DeunaWidgetMethod, config: Record<string, unknown>) => DeunaProcessor;
165
- /** `paymentMethods` of `initPaymentWidget` for a processor. */
166
- declare const deunaWidgetPaymentMethods: (processor: DeunaProcessor) => DeunaWidgetPaymentMethod[];
179
+ /**
180
+ * `paymentMethods` of `initPaymentWidget`: one entry per widget method, with
181
+ * the DEUNA processors of every configured processor that uses it. One entry
182
+ * opens its form directly; several let the customer choose.
183
+ */
184
+ declare const deunaWidgetPaymentMethods: (processors: DeunaProcessor | readonly DeunaProcessor[]) => DeunaWidgetPaymentMethod[];
185
+ /** Our processor key for the processor DEUNA reports on the order. */
186
+ declare const deunaProcessorFromState: (candidates: readonly DeunaProcessor[], reported: string | null | undefined) => DeunaProcessor | null;
167
187
  /**
168
188
  * DEUNA Payment Widget for every method (card, Nequi, Mercado Pago, Deuna
169
189
  * App Wallet, PSE). Spark tokenizes the DEUNA order with the private key
@@ -300,4 +320,4 @@ declare const deunaStateError: (input: {
300
320
  attempt: number;
301
321
  }) => StandardPaymentError;
302
322
  //#endregion
303
- export { DEUNA_PROCESSORS, DEUNA_PROCESSOR_KEYS, DEUNA_PROVIDER, DEUNA_WIDGET_POLICY, type DeunaCallbackUrls, type DeunaOrderState, type DeunaPaymentStatus, DeunaProcessor, DeunaStatusMapping, type DeunaTokenizeInput, type DeunaTokenizeOutput, type DeunaWidgetApi, type DeunaWidgetBridge, type DeunaWidgetLanguage, type DeunaWidgetMethod, type DeunaWidgetOpenInput, DeunaWidgetOptions, type DeunaWidgetOutcome, type DeunaWidgetPaymentMethod, deunaDeclinedCode, deunaErrors, deunaProcessorsFor, deunaStateError, deunaWidgetPaymentMethods, deunaWidgetPayments, mapDeunaStatus, orderTokenKey, resolveDeunaProcessor };
323
+ export { DEUNA_PROCESSORS, DEUNA_PROCESSOR_KEYS, DEUNA_PROVIDER, DEUNA_WIDGET_POLICY, type DeunaCallbackUrls, type DeunaOrderState, type DeunaPaymentStatus, DeunaProcessor, DeunaStatusMapping, type DeunaTokenizeInput, type DeunaTokenizeOutput, type DeunaWidgetApi, type DeunaWidgetBridge, type DeunaWidgetLanguage, type DeunaWidgetMethod, type DeunaWidgetOpenInput, DeunaWidgetOptions, type DeunaWidgetOutcome, type DeunaWidgetPaymentMethod, deunaDeclinedCode, deunaErrors, deunaProcessorFromState, deunaProcessorsFor, deunaStateError, deunaWidgetPaymentMethods, deunaWidgetPayments, mapDeunaStatus, orderTokenKey, resolveDeunaProcessor, resolveDeunaProcessors };
package/dist/index.js CHANGED
@@ -246,26 +246,75 @@ const deunaProcessorsFor = (method) => {
246
246
  return DEUNA_PROCESSORS[key].method === method;
247
247
  });
248
248
  };
249
- /** `payments.config.processor`; optional when the method has only one. */
250
- const resolveDeunaProcessor = (method, config) => {
251
- const allowed = deunaProcessorsFor(method);
252
- const value = config.processor;
253
- const known = allowed.find((key) => key === value);
254
- if (known) return known;
255
- const only = allowed.length === 1 ? allowed[0] : void 0;
256
- if (value == null && only) return only;
249
+ /** `config.processors`, else the legacy single `config.processor`. */
250
+ const configuredValues = (config) => {
251
+ if (Array.isArray(config.processors)) return config.processors;
252
+ return config.processor == null ? [] : [config.processor];
253
+ };
254
+ const unsupported = (method, value) => {
257
255
  const message = `Unsupported DEUNA processor for ${method}: ${String(value)}`;
258
- throw fail("INVALID_REQUEST", message);
256
+ return fail("INVALID_REQUEST", message);
257
+ };
258
+ /**
259
+ * Processors one charge opens the widget with. `config.processors` lists
260
+ * the processors the payment enables (same DEUNA credentials); a channel
261
+ * that shows one option per processor sets the customer's pick in
262
+ * `config.processor`, which wins: the widget opens only that one. Without
263
+ * a pick every enabled processor is offered and the customer chooses in
264
+ * the widget. A legacy payment has only `config.processor`; it is
265
+ * optional when the method has one processor. Kept in `DEUNA_PROCESSORS`
266
+ * order.
267
+ */
268
+ const resolveDeunaProcessors = (method, config) => {
269
+ const allowed = deunaProcessorsFor(method);
270
+ const values = configuredValues(config);
271
+ const unknown = values.find((value) => !allowed.some((key) => key === value));
272
+ if (unknown !== void 0) throw unsupported(method, unknown);
273
+ const enabled = allowed.filter((key) => values.includes(key));
274
+ if (config.processor != null) {
275
+ const chosen = allowed.find((key) => key === config.processor);
276
+ if (!chosen) throw unsupported(method, config.processor);
277
+ if (enabled.length && !enabled.includes(chosen)) {
278
+ const message = `DEUNA processor ${chosen} is not enabled for ${method}`;
279
+ throw fail("INVALID_REQUEST", message);
280
+ }
281
+ return [chosen];
282
+ }
283
+ if (enabled.length) return enabled;
284
+ if (allowed.length === 1) return allowed;
285
+ throw fail("INVALID_REQUEST", `Missing DEUNA processor for ${method}`);
286
+ };
287
+ /** @deprecated Use `resolveDeunaProcessors`: first configured processor. */
288
+ const resolveDeunaProcessor = (method, config) => {
289
+ return resolveDeunaProcessors(method, config)[0];
290
+ };
291
+ /**
292
+ * `paymentMethods` of `initPaymentWidget`: one entry per widget method, with
293
+ * the DEUNA processors of every configured processor that uses it. One entry
294
+ * opens its form directly; several let the customer choose.
295
+ */
296
+ const deunaWidgetPaymentMethods = (processors) => {
297
+ const list = typeof processors === "string" ? [processors] : processors;
298
+ const entries = [];
299
+ for (const processor of list) {
300
+ const entry = DEUNA_PROCESSORS[processor];
301
+ const found = entries.find((e) => e.paymentMethod === entry.paymentMethod);
302
+ const target = found ?? { paymentMethod: entry.paymentMethod };
303
+ if (!found) entries.push(target);
304
+ if (!entry.processors.length) continue;
305
+ target.processors = [...target.processors ?? [], ...entry.processors];
306
+ }
307
+ return entries;
259
308
  };
260
- /** `paymentMethods` of `initPaymentWidget` for a processor. */
261
- const deunaWidgetPaymentMethods = (processor) => {
262
- const entry = DEUNA_PROCESSORS[processor];
263
- const base = { paymentMethod: entry.paymentMethod };
264
- if (!entry.processors.length) return [base];
265
- return [{
266
- ...base,
267
- processors: [...entry.processors]
268
- }];
309
+ /** Our processor key for the processor DEUNA reports on the order. */
310
+ const deunaProcessorFromState = (candidates, reported) => {
311
+ if (candidates.length === 1) return candidates[0] ?? null;
312
+ if (!reported) return null;
313
+ const value = reported.toLowerCase();
314
+ return candidates.find((key) => {
315
+ const names = DEUNA_PROCESSORS[key].processors;
316
+ return key === value || names.includes(value);
317
+ }) ?? null;
269
318
  };
270
319
  const publicKeyOf = (config) => {
271
320
  const key = config.public_key;
@@ -273,7 +322,7 @@ const publicKeyOf = (config) => {
273
322
  throw fail("INVALID_CREDENTIALS", "Missing DEUNA public_key");
274
323
  };
275
324
  /** Card brand and last 4 are not exposed by the widget: no card details. */
276
- const detailsOf = (charge, reference) => {
325
+ const detailsOf = (charge, processor, reference) => {
277
326
  if (charge.method === "CARD") return null;
278
327
  if (charge.method === "BANK_TRANSFER") return {
279
328
  method: "BANK_TRANSFER",
@@ -281,7 +330,7 @@ const detailsOf = (charge, reference) => {
281
330
  };
282
331
  return {
283
332
  method: "WALLET",
284
- wallet: charge.processor,
333
+ wallet: processor ?? "deuna",
285
334
  reference
286
335
  };
287
336
  };
@@ -290,9 +339,12 @@ const toResult = (ctx, charge, state, base) => {
290
339
  const mapped = mapDeunaStatus(state.status, charge.method);
291
340
  const transactionId = state.transaction_id ?? null;
292
341
  const previous = record(base?.metadata.provider);
342
+ const known = deunaProcessorFromState(charge.processors, state.processor);
343
+ const kept = typeof previous.processor === "string" ? previous.processor : null;
344
+ const processor = known ?? kept;
293
345
  const p1 = {
294
346
  order_token: state.order_token,
295
- processor: charge.processor
347
+ processor
296
348
  };
297
349
  const p2 = {
298
350
  status: state.status,
@@ -314,7 +366,7 @@ const toResult = (ctx, charge, state, base) => {
314
366
  provider
315
367
  };
316
368
  const amount = base?.amount ?? ctx.amount.value;
317
- const details = detailsOf(charge, reference);
369
+ const details = detailsOf(charge, processor, reference);
318
370
  if (mapped.status !== "FAILED") return {
319
371
  status: mapped.status,
320
372
  amount,
@@ -369,7 +421,7 @@ const deunaWidgetPayments = (options) => {
369
421
  const chargeOf = (ctx) => {
370
422
  return {
371
423
  method,
372
- processor: resolveDeunaProcessor(method, ctx.config)
424
+ processors: resolveDeunaProcessors(method, ctx.config)
373
425
  };
374
426
  };
375
427
  const orderState = (ctx, orderToken) => {
@@ -426,7 +478,7 @@ const deunaWidgetPayments = (options) => {
426
478
  ...t3
427
479
  })).order_token;
428
480
  await ctx.storage.set(orderTokenKey(ctx.attemptReference), orderToken);
429
- const paymentMethods = deunaWidgetPaymentMethods(charge.processor);
481
+ const paymentMethods = deunaWidgetPaymentMethods(charge.processors);
430
482
  const o1 = {
431
483
  publicApiKey,
432
484
  environment: ctx.environment,
@@ -456,6 +508,16 @@ const deunaWidgetPayments = (options) => {
456
508
  status: "CANCELLED"
457
509
  };
458
510
  };
511
+ /**
512
+ * A paid DEUNA charge is reversed by Spark with the private key when the
513
+ * order is cancelled or refunded (`server`); DaviPlata has no refund API
514
+ * (`manual`). An unpaid one is only dropped on the device.
515
+ */
516
+ const reversalFor = (result) => {
517
+ if (result.status !== "PAID") return "cancel";
518
+ if (record(result.metadata.provider).processor === "daviplata") return "manual";
519
+ return "server";
520
+ };
459
521
  return {
460
522
  provider: DEUNA_PROVIDER,
461
523
  method,
@@ -463,8 +525,9 @@ const deunaWidgetPayments = (options) => {
463
525
  policy: DEUNA_WIDGET_POLICY,
464
526
  start,
465
527
  query,
466
- cancel
528
+ cancel,
529
+ reversalFor
467
530
  };
468
531
  };
469
532
  //#endregion
470
- export { DEUNA_PROCESSORS, DEUNA_PROCESSOR_KEYS, DEUNA_PROVIDER, DEUNA_WIDGET_POLICY, deunaDeclinedCode, deunaErrors, deunaProcessorsFor, deunaStateError, deunaWidgetPaymentMethods, deunaWidgetPayments, mapDeunaStatus, orderTokenKey, resolveDeunaProcessor };
533
+ export { DEUNA_PROCESSORS, DEUNA_PROCESSOR_KEYS, DEUNA_PROVIDER, DEUNA_WIDGET_POLICY, deunaDeclinedCode, deunaErrors, deunaProcessorFromState, deunaProcessorsFor, deunaStateError, deunaWidgetPaymentMethods, deunaWidgetPayments, mapDeunaStatus, orderTokenKey, resolveDeunaProcessor, resolveDeunaProcessors };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fire-spark/payments-deuna-widget",
3
- "version": "0.12.0",
3
+ "version": "0.12.2",
4
4
  "description": "Fire Spark DEUNA Payment Widget adapter: cards, Nequi, Mercado Pago, Deuna App Wallet and DaviPlata, and PSE through the DEUNA checkout",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -17,8 +17,8 @@
17
17
  }
18
18
  },
19
19
  "dependencies": {
20
- "@fire-spark/payments": "^0.12.0",
21
- "@fire-spark/types": "^0.12.0"
20
+ "@fire-spark/payments": "^0.12.2",
21
+ "@fire-spark/types": "^0.12.2"
22
22
  },
23
23
  "devDependencies": {
24
24
  "tsdown": "^0.22.14",