@sakeetech/viva-payments-core 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +413 -0
- package/dist/auth/http.d.ts +44 -0
- package/dist/auth/http.d.ts.map +1 -0
- package/dist/auth/http.js +80 -0
- package/dist/auth/http.js.map +1 -0
- package/dist/auth/index.d.ts +19 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +18 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/oauth2-strategy.d.ts +117 -0
- package/dist/auth/oauth2-strategy.d.ts.map +1 -0
- package/dist/auth/oauth2-strategy.js +217 -0
- package/dist/auth/oauth2-strategy.js.map +1 -0
- package/dist/auth/reseller-strategy.d.ts +65 -0
- package/dist/auth/reseller-strategy.d.ts.map +1 -0
- package/dist/auth/reseller-strategy.js +68 -0
- package/dist/auth/reseller-strategy.js.map +1 -0
- package/dist/auth/single-flight.d.ts +81 -0
- package/dist/auth/single-flight.d.ts.map +1 -0
- package/dist/auth/single-flight.js +160 -0
- package/dist/auth/single-flight.js.map +1 -0
- package/dist/auth/token-cache.d.ts +50 -0
- package/dist/auth/token-cache.d.ts.map +1 -0
- package/dist/auth/token-cache.js +59 -0
- package/dist/auth/token-cache.js.map +1 -0
- package/dist/errors/api-error.d.ts +15 -0
- package/dist/errors/api-error.d.ts.map +1 -0
- package/dist/errors/api-error.js +18 -0
- package/dist/errors/api-error.js.map +1 -0
- package/dist/errors/auth-error.d.ts +14 -0
- package/dist/errors/auth-error.d.ts.map +1 -0
- package/dist/errors/auth-error.js +17 -0
- package/dist/errors/auth-error.js.map +1 -0
- package/dist/errors/base.d.ts +59 -0
- package/dist/errors/base.d.ts.map +1 -0
- package/dist/errors/base.js +51 -0
- package/dist/errors/base.js.map +1 -0
- package/dist/errors/index.d.ts +18 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +16 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/errors/mode-mismatch-error.d.ts +19 -0
- package/dist/errors/mode-mismatch-error.d.ts.map +1 -0
- package/dist/errors/mode-mismatch-error.js +22 -0
- package/dist/errors/mode-mismatch-error.js.map +1 -0
- package/dist/errors/rate-limit-error.d.ts +20 -0
- package/dist/errors/rate-limit-error.d.ts.map +1 -0
- package/dist/errors/rate-limit-error.js +20 -0
- package/dist/errors/rate-limit-error.js.map +1 -0
- package/dist/errors/validation-error.d.ts +14 -0
- package/dist/errors/validation-error.d.ts.map +1 -0
- package/dist/errors/validation-error.js +17 -0
- package/dist/errors/validation-error.js.map +1 -0
- package/dist/errors/webhook-error.d.ts +14 -0
- package/dist/errors/webhook-error.d.ts.map +1 -0
- package/dist/errors/webhook-error.js +17 -0
- package/dist/errors/webhook-error.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/isv/accounts.d.ts +38 -0
- package/dist/isv/accounts.d.ts.map +1 -0
- package/dist/isv/accounts.js +60 -0
- package/dist/isv/accounts.js.map +1 -0
- package/dist/isv/client.d.ts +187 -0
- package/dist/isv/client.d.ts.map +1 -0
- package/dist/isv/client.js +465 -0
- package/dist/isv/client.js.map +1 -0
- package/dist/isv/index.d.ts +52 -0
- package/dist/isv/index.d.ts.map +1 -0
- package/dist/isv/index.js +53 -0
- package/dist/isv/index.js.map +1 -0
- package/dist/isv/legacy-basic-client.d.ts +122 -0
- package/dist/isv/legacy-basic-client.d.ts.map +1 -0
- package/dist/isv/legacy-basic-client.js +281 -0
- package/dist/isv/legacy-basic-client.js.map +1 -0
- package/dist/isv/payments.d.ts +199 -0
- package/dist/isv/payments.d.ts.map +1 -0
- package/dist/isv/payments.js +385 -0
- package/dist/isv/payments.js.map +1 -0
- package/dist/isv/sources.d.ts +80 -0
- package/dist/isv/sources.d.ts.map +1 -0
- package/dist/isv/sources.js +112 -0
- package/dist/isv/sources.js.map +1 -0
- package/dist/isv/webhooks-api.d.ts +48 -0
- package/dist/isv/webhooks-api.d.ts.map +1 -0
- package/dist/isv/webhooks-api.js +66 -0
- package/dist/isv/webhooks-api.js.map +1 -0
- package/dist/legacy/client.d.ts +199 -0
- package/dist/legacy/client.d.ts.map +1 -0
- package/dist/legacy/client.js +351 -0
- package/dist/legacy/client.js.map +1 -0
- package/dist/legacy/index.d.ts +15 -0
- package/dist/legacy/index.d.ts.map +1 -0
- package/dist/legacy/index.js +14 -0
- package/dist/legacy/index.js.map +1 -0
- package/dist/observability/context.d.ts +30 -0
- package/dist/observability/context.d.ts.map +1 -0
- package/dist/observability/context.js +40 -0
- package/dist/observability/context.js.map +1 -0
- package/dist/observability/index.d.ts +15 -0
- package/dist/observability/index.d.ts.map +1 -0
- package/dist/observability/index.js +11 -0
- package/dist/observability/index.js.map +1 -0
- package/dist/observability/logger.d.ts +81 -0
- package/dist/observability/logger.d.ts.map +1 -0
- package/dist/observability/logger.js +127 -0
- package/dist/observability/logger.js.map +1 -0
- package/dist/observability/metrics.d.ts +37 -0
- package/dist/observability/metrics.d.ts.map +1 -0
- package/dist/observability/metrics.js +40 -0
- package/dist/observability/metrics.js.map +1 -0
- package/dist/observability/redact.d.ts +21 -0
- package/dist/observability/redact.d.ts.map +1 -0
- package/dist/observability/redact.js +72 -0
- package/dist/observability/redact.js.map +1 -0
- package/dist/observability/tracer.d.ts +25 -0
- package/dist/observability/tracer.d.ts.map +1 -0
- package/dist/observability/tracer.js +18 -0
- package/dist/observability/tracer.js.map +1 -0
- package/dist/payments/client.d.ts +247 -0
- package/dist/payments/client.d.ts.map +1 -0
- package/dist/payments/client.js +488 -0
- package/dist/payments/client.js.map +1 -0
- package/dist/payments/index.d.ts +14 -0
- package/dist/payments/index.d.ts.map +1 -0
- package/dist/payments/index.js +13 -0
- package/dist/payments/index.js.map +1 -0
- package/dist/refunds/fast-refund-client.d.ts +128 -0
- package/dist/refunds/fast-refund-client.d.ts.map +1 -0
- package/dist/refunds/fast-refund-client.js +138 -0
- package/dist/refunds/fast-refund-client.js.map +1 -0
- package/dist/refunds/index.d.ts +19 -0
- package/dist/refunds/index.d.ts.map +1 -0
- package/dist/refunds/index.js +17 -0
- package/dist/refunds/index.js.map +1 -0
- package/dist/refunds/strategy.d.ts +78 -0
- package/dist/refunds/strategy.d.ts.map +1 -0
- package/dist/refunds/strategy.js +75 -0
- package/dist/refunds/strategy.js.map +1 -0
- package/dist/types/auth.d.ts +80 -0
- package/dist/types/auth.d.ts.map +1 -0
- package/dist/types/auth.js +12 -0
- package/dist/types/auth.js.map +1 -0
- package/dist/types/card-types.d.ts +48 -0
- package/dist/types/card-types.d.ts.map +1 -0
- package/dist/types/card-types.js +62 -0
- package/dist/types/card-types.js.map +1 -0
- package/dist/types/common.d.ts +160 -0
- package/dist/types/common.d.ts.map +1 -0
- package/dist/types/common.js +70 -0
- package/dist/types/common.js.map +1 -0
- package/dist/types/index.d.ts +21 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +21 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/isv-accounts.d.ts +109 -0
- package/dist/types/isv-accounts.d.ts.map +1 -0
- package/dist/types/isv-accounts.js +22 -0
- package/dist/types/isv-accounts.js.map +1 -0
- package/dist/types/isv-payments.d.ts +262 -0
- package/dist/types/isv-payments.d.ts.map +1 -0
- package/dist/types/isv-payments.js +19 -0
- package/dist/types/isv-payments.js.map +1 -0
- package/dist/types/status.d.ts +125 -0
- package/dist/types/status.d.ts.map +1 -0
- package/dist/types/status.js +19 -0
- package/dist/types/status.js.map +1 -0
- package/dist/types/webhook-events.d.ts +447 -0
- package/dist/types/webhook-events.d.ts.map +1 -0
- package/dist/types/webhook-events.js +76 -0
- package/dist/types/webhook-events.js.map +1 -0
- package/dist/webhooks/challenge-response.d.ts +28 -0
- package/dist/webhooks/challenge-response.d.ts.map +1 -0
- package/dist/webhooks/challenge-response.js +35 -0
- package/dist/webhooks/challenge-response.js.map +1 -0
- package/dist/webhooks/event-types.d.ts +44 -0
- package/dist/webhooks/event-types.d.ts.map +1 -0
- package/dist/webhooks/event-types.js +50 -0
- package/dist/webhooks/event-types.js.map +1 -0
- package/dist/webhooks/extract-client-ip.d.ts +40 -0
- package/dist/webhooks/extract-client-ip.d.ts.map +1 -0
- package/dist/webhooks/extract-client-ip.js +72 -0
- package/dist/webhooks/extract-client-ip.js.map +1 -0
- package/dist/webhooks/hmac-verify.d.ts +38 -0
- package/dist/webhooks/hmac-verify.d.ts.map +1 -0
- package/dist/webhooks/hmac-verify.js +92 -0
- package/dist/webhooks/hmac-verify.js.map +1 -0
- package/dist/webhooks/index.d.ts +19 -0
- package/dist/webhooks/index.d.ts.map +1 -0
- package/dist/webhooks/index.js +19 -0
- package/dist/webhooks/index.js.map +1 -0
- package/dist/webhooks/ip-allowlist.d.ts +59 -0
- package/dist/webhooks/ip-allowlist.d.ts.map +1 -0
- package/dist/webhooks/ip-allowlist.js +147 -0
- package/dist/webhooks/ip-allowlist.js.map +1 -0
- package/dist/webhooks/status-lattice.d.ts +72 -0
- package/dist/webhooks/status-lattice.d.ts.map +1 -0
- package/dist/webhooks/status-lattice.js +208 -0
- package/dist/webhooks/status-lattice.js.map +1 -0
- package/package.json +85 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FastRefundClient — Viva Fast Refund API (OAuth2 acquiring scopes).
|
|
3
|
+
*
|
|
4
|
+
* Wraps `POST /acquiring/v1/transactions/{transactionId}:fastrefund` on the
|
|
5
|
+
* v2 API surface. Requires an OAuth2 token with `acquiring` +
|
|
6
|
+
* `acquiring:transactions` scopes (see AUTH.md §3.2). Eligibility is
|
|
7
|
+
* server-enforced by Viva:
|
|
8
|
+
* - Visa / MasterCard / Maestro card schemes
|
|
9
|
+
* - E-commerce (card-not-present) transactions
|
|
10
|
+
* - Merchant must be approved by Viva sales for fast refunds
|
|
11
|
+
*
|
|
12
|
+
* If the merchant is not approved or the original transaction is not eligible,
|
|
13
|
+
* Viva returns HTTP 403. Callers are expected to catch the resulting
|
|
14
|
+
* `VivaApiError` and fall back to the standard (legacy) refund path. See
|
|
15
|
+
* {@link resolveRefundStrategy} for the upstream pure decision helper.
|
|
16
|
+
*
|
|
17
|
+
* Design notes:
|
|
18
|
+
* - Caller-driven fallback: this client never silently retries on a
|
|
19
|
+
* standard refund — caller decides whether to fall back.
|
|
20
|
+
* - Idempotent: `false`. POST is non-idempotent at the transport layer; no
|
|
21
|
+
* 4xx/5xx retries. Connection-level errors retry once (request never acked).
|
|
22
|
+
* - Mirrors the style of {@link BasicAuthClient.request} / Payments.refundPayment
|
|
23
|
+
* for validation, error handling, and JSDoc references.
|
|
24
|
+
*
|
|
25
|
+
* @see docs/ENDPOINTS.md §4 (Fast vs Standard refund matrix)
|
|
26
|
+
* @see docs/AUTH.md §3.2 (OAuth2 acquiring scopes)
|
|
27
|
+
* @see docs/plans/multi-mode-v0.md §8.5a (FastRefundClient class shape)
|
|
28
|
+
* @see docs/STATE-MACHINE.md §3.1 (card-scheme detection)
|
|
29
|
+
* @see references/payment-api.yaml:9255 (POST /acquiring/v1/transactions/{id}:fastrefund)
|
|
30
|
+
* @see references/payment-api.yaml:9268 (eligibility — Visa/MC/Maestro)
|
|
31
|
+
*/
|
|
32
|
+
import type { IsvHttpClient } from '../isv/client.js';
|
|
33
|
+
import type { TransactionId, MinorUnits } from '../types/index.js';
|
|
34
|
+
export interface FastRefundClientConfig {
|
|
35
|
+
/**
|
|
36
|
+
* OAuth2 HTTP client whose underlying AuthStrategy yields a token with
|
|
37
|
+
* `acquiring` + `acquiring:transactions` scopes (see AUTH.md §3.2).
|
|
38
|
+
*/
|
|
39
|
+
client: IsvHttpClient;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Input for {@link FastRefundClient.refund}.
|
|
43
|
+
*
|
|
44
|
+
* All fields are required — Fast Refund does not support a "full refund by
|
|
45
|
+
* omission" convention (unlike the legacy refund path). Pass the original
|
|
46
|
+
* transaction's full amount in minor units for a full refund.
|
|
47
|
+
*/
|
|
48
|
+
export interface FastRefundRequest {
|
|
49
|
+
/** UUID of the ORIGINAL captured transaction to refund. */
|
|
50
|
+
transactionId: TransactionId;
|
|
51
|
+
/** Amount in integer minor units. Must be > 0. */
|
|
52
|
+
amount: MinorUnits;
|
|
53
|
+
/** Payment source code (Viva merchant source). Non-empty string. */
|
|
54
|
+
sourceCode: string;
|
|
55
|
+
/** Merchant-side reference for the refund. Non-empty string. */
|
|
56
|
+
merchantTrns: string;
|
|
57
|
+
/**
|
|
58
|
+
* Idempotency key. Forwarded as the `Idempotency-Key` HTTP header per the
|
|
59
|
+
* shared {@link IsvHttpClient} convention. Non-empty string.
|
|
60
|
+
*
|
|
61
|
+
* NOTE: Viva does not appear to deduplicate server-side (probe F2,
|
|
62
|
+
* 2026-04-25). Local dedup remains the authoritative mechanism. Header is
|
|
63
|
+
* retained for forward-compat.
|
|
64
|
+
*/
|
|
65
|
+
idempotencyKey: string;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Response from {@link FastRefundClient.refund}.
|
|
69
|
+
*
|
|
70
|
+
* Field names are normalized to camelCase. Viva responds with a transaction
|
|
71
|
+
* envelope describing the REFUND transaction (a new transaction id, distinct
|
|
72
|
+
* from the original `transactionId` passed in the request).
|
|
73
|
+
*
|
|
74
|
+
* @see references/payment-api.yaml:9255
|
|
75
|
+
*/
|
|
76
|
+
export interface FastRefundResponse {
|
|
77
|
+
/** The refund transaction's OWN id (not the original captured transaction). */
|
|
78
|
+
transactionId: TransactionId;
|
|
79
|
+
/** Viva event id correlated with the refund. */
|
|
80
|
+
eventId: number;
|
|
81
|
+
/** Refunded amount in minor units, as JSON number from Viva. */
|
|
82
|
+
amount: number;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Thin POST wrapper for the Viva Fast Refund endpoint.
|
|
86
|
+
*
|
|
87
|
+
* Eligibility (per Viva docs):
|
|
88
|
+
* - Visa / MasterCard / Maestro
|
|
89
|
+
* - E-commerce (card-not-present)
|
|
90
|
+
* - Merchant approved by Viva sales for Fast Refunds
|
|
91
|
+
*
|
|
92
|
+
* On 403 the caller should fall back to the standard refund flow
|
|
93
|
+
* (`Payments.refundPayment` via the legacy `BasicAuthClient`). The decision
|
|
94
|
+
* helper {@link resolveRefundStrategy} returns `auto-ineligible-*` reasons up
|
|
95
|
+
* front so most ineligible cases never reach the wire.
|
|
96
|
+
*
|
|
97
|
+
* @see references/payment-api.yaml:9255
|
|
98
|
+
* @see docs/ENDPOINTS.md §4
|
|
99
|
+
* @see docs/AUTH.md §3.2
|
|
100
|
+
*/
|
|
101
|
+
export declare class FastRefundClient {
|
|
102
|
+
private readonly client;
|
|
103
|
+
constructor(config: FastRefundClientConfig);
|
|
104
|
+
/**
|
|
105
|
+
* POST `/acquiring/v1/transactions/{transactionId}:fastrefund`.
|
|
106
|
+
*
|
|
107
|
+
* Body: `{ amount, sourceCode, merchantTrns, idempotencyKey }` — no extra
|
|
108
|
+
* fields. Auth: OAuth2 Bearer (acquiring scopes) handled by the underlying
|
|
109
|
+
* {@link IsvHttpClient}.
|
|
110
|
+
*
|
|
111
|
+
* Local validation (throws VivaValidationError before HTTP call):
|
|
112
|
+
* - `amount` must be > 0 minor units
|
|
113
|
+
* - `sourceCode`, `merchantTrns`, `idempotencyKey` must be non-empty strings
|
|
114
|
+
*
|
|
115
|
+
* Errors:
|
|
116
|
+
* - 403 → VivaApiError. Caller decides whether to fall back to standard refund.
|
|
117
|
+
* - 404 → VivaApiError (transaction not found).
|
|
118
|
+
* - 422 → VivaApiError (invalid BIN / scheme).
|
|
119
|
+
* - 423 → VivaApiError (refund already in progress).
|
|
120
|
+
* - 452 → VivaApiError (insufficient funds for fast refund).
|
|
121
|
+
* - 5xx → VivaApiError (no retry — POST is non-idempotent).
|
|
122
|
+
*
|
|
123
|
+
* @see references/payment-api.yaml:9255
|
|
124
|
+
* @see docs/ERRORS.md §2 (error code matrix)
|
|
125
|
+
*/
|
|
126
|
+
refund(input: FastRefundRequest): Promise<FastRefundResponse>;
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=fast-refund-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fast-refund-client.d.ts","sourceRoot":"","sources":["../../src/refunds/fast-refund-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAOnE,MAAM,WAAW,sBAAsB;IACrC;;;OAGG;IACH,MAAM,EAAE,aAAa,CAAC;CACvB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,iBAAiB;IAChC,2DAA2D;IAC3D,aAAa,EAAE,aAAa,CAAC;IAC7B,kDAAkD;IAClD,MAAM,EAAE,UAAU,CAAC;IACnB,oEAAoE;IACpE,UAAU,EAAE,MAAM,CAAC;IACnB,gEAAgE;IAChE,YAAY,EAAE,MAAM,CAAC;IACrB;;;;;;;OAOG;IACH,cAAc,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,kBAAkB;IACjC,+EAA+E;IAC/E,aAAa,EAAE,aAAa,CAAC;IAC7B,gDAAgD;IAChD,OAAO,EAAE,MAAM,CAAC;IAChB,gEAAgE;IAChE,MAAM,EAAE,MAAM,CAAC;CAChB;AAMD;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;gBAE3B,MAAM,EAAE,sBAAsB;IAI1C;;;;;;;;;;;;;;;;;;;;;OAqBG;IACG,MAAM,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;CA0EpE"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FastRefundClient — Viva Fast Refund API (OAuth2 acquiring scopes).
|
|
3
|
+
*
|
|
4
|
+
* Wraps `POST /acquiring/v1/transactions/{transactionId}:fastrefund` on the
|
|
5
|
+
* v2 API surface. Requires an OAuth2 token with `acquiring` +
|
|
6
|
+
* `acquiring:transactions` scopes (see AUTH.md §3.2). Eligibility is
|
|
7
|
+
* server-enforced by Viva:
|
|
8
|
+
* - Visa / MasterCard / Maestro card schemes
|
|
9
|
+
* - E-commerce (card-not-present) transactions
|
|
10
|
+
* - Merchant must be approved by Viva sales for fast refunds
|
|
11
|
+
*
|
|
12
|
+
* If the merchant is not approved or the original transaction is not eligible,
|
|
13
|
+
* Viva returns HTTP 403. Callers are expected to catch the resulting
|
|
14
|
+
* `VivaApiError` and fall back to the standard (legacy) refund path. See
|
|
15
|
+
* {@link resolveRefundStrategy} for the upstream pure decision helper.
|
|
16
|
+
*
|
|
17
|
+
* Design notes:
|
|
18
|
+
* - Caller-driven fallback: this client never silently retries on a
|
|
19
|
+
* standard refund — caller decides whether to fall back.
|
|
20
|
+
* - Idempotent: `false`. POST is non-idempotent at the transport layer; no
|
|
21
|
+
* 4xx/5xx retries. Connection-level errors retry once (request never acked).
|
|
22
|
+
* - Mirrors the style of {@link BasicAuthClient.request} / Payments.refundPayment
|
|
23
|
+
* for validation, error handling, and JSDoc references.
|
|
24
|
+
*
|
|
25
|
+
* @see docs/ENDPOINTS.md §4 (Fast vs Standard refund matrix)
|
|
26
|
+
* @see docs/AUTH.md §3.2 (OAuth2 acquiring scopes)
|
|
27
|
+
* @see docs/plans/multi-mode-v0.md §8.5a (FastRefundClient class shape)
|
|
28
|
+
* @see docs/STATE-MACHINE.md §3.1 (card-scheme detection)
|
|
29
|
+
* @see references/payment-api.yaml:9255 (POST /acquiring/v1/transactions/{id}:fastrefund)
|
|
30
|
+
* @see references/payment-api.yaml:9268 (eligibility — Visa/MC/Maestro)
|
|
31
|
+
*/
|
|
32
|
+
import { VivaValidationError } from '../errors/index.js';
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
// FastRefundClient
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
/**
|
|
37
|
+
* Thin POST wrapper for the Viva Fast Refund endpoint.
|
|
38
|
+
*
|
|
39
|
+
* Eligibility (per Viva docs):
|
|
40
|
+
* - Visa / MasterCard / Maestro
|
|
41
|
+
* - E-commerce (card-not-present)
|
|
42
|
+
* - Merchant approved by Viva sales for Fast Refunds
|
|
43
|
+
*
|
|
44
|
+
* On 403 the caller should fall back to the standard refund flow
|
|
45
|
+
* (`Payments.refundPayment` via the legacy `BasicAuthClient`). The decision
|
|
46
|
+
* helper {@link resolveRefundStrategy} returns `auto-ineligible-*` reasons up
|
|
47
|
+
* front so most ineligible cases never reach the wire.
|
|
48
|
+
*
|
|
49
|
+
* @see references/payment-api.yaml:9255
|
|
50
|
+
* @see docs/ENDPOINTS.md §4
|
|
51
|
+
* @see docs/AUTH.md §3.2
|
|
52
|
+
*/
|
|
53
|
+
export class FastRefundClient {
|
|
54
|
+
client;
|
|
55
|
+
constructor(config) {
|
|
56
|
+
this.client = config.client;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* POST `/acquiring/v1/transactions/{transactionId}:fastrefund`.
|
|
60
|
+
*
|
|
61
|
+
* Body: `{ amount, sourceCode, merchantTrns, idempotencyKey }` — no extra
|
|
62
|
+
* fields. Auth: OAuth2 Bearer (acquiring scopes) handled by the underlying
|
|
63
|
+
* {@link IsvHttpClient}.
|
|
64
|
+
*
|
|
65
|
+
* Local validation (throws VivaValidationError before HTTP call):
|
|
66
|
+
* - `amount` must be > 0 minor units
|
|
67
|
+
* - `sourceCode`, `merchantTrns`, `idempotencyKey` must be non-empty strings
|
|
68
|
+
*
|
|
69
|
+
* Errors:
|
|
70
|
+
* - 403 → VivaApiError. Caller decides whether to fall back to standard refund.
|
|
71
|
+
* - 404 → VivaApiError (transaction not found).
|
|
72
|
+
* - 422 → VivaApiError (invalid BIN / scheme).
|
|
73
|
+
* - 423 → VivaApiError (refund already in progress).
|
|
74
|
+
* - 452 → VivaApiError (insufficient funds for fast refund).
|
|
75
|
+
* - 5xx → VivaApiError (no retry — POST is non-idempotent).
|
|
76
|
+
*
|
|
77
|
+
* @see references/payment-api.yaml:9255
|
|
78
|
+
* @see docs/ERRORS.md §2 (error code matrix)
|
|
79
|
+
*/
|
|
80
|
+
async refund(input) {
|
|
81
|
+
// --- local validation (mirror style of Payments.refundPayment / createOrder) ---
|
|
82
|
+
if (input.amount <= 0n) {
|
|
83
|
+
throw new VivaValidationError({
|
|
84
|
+
message: `FastRefundClient.refund: amount must be > 0 minor units, got ${input.amount}`,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
if (typeof input.sourceCode !== 'string' || input.sourceCode.length === 0) {
|
|
88
|
+
throw new VivaValidationError({
|
|
89
|
+
message: 'FastRefundClient.refund: sourceCode must be a non-empty string',
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
if (typeof input.merchantTrns !== 'string' || input.merchantTrns.length === 0) {
|
|
93
|
+
throw new VivaValidationError({
|
|
94
|
+
message: 'FastRefundClient.refund: merchantTrns must be a non-empty string',
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
if (typeof input.idempotencyKey !== 'string' || input.idempotencyKey.length === 0) {
|
|
98
|
+
throw new VivaValidationError({
|
|
99
|
+
message: 'FastRefundClient.refund: idempotencyKey must be a non-empty string',
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
if (typeof input.transactionId !== 'string' || input.transactionId.length === 0) {
|
|
103
|
+
throw new VivaValidationError({
|
|
104
|
+
message: 'FastRefundClient.refund: transactionId must be a non-empty string',
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
// URL-encode the transactionId so the path segment is safe even for ids
|
|
108
|
+
// that contain reserved characters (defensive — Viva UUIDs do not, but
|
|
109
|
+
// the type is a branded string so future ids could).
|
|
110
|
+
const encodedId = encodeURIComponent(input.transactionId);
|
|
111
|
+
const path = `/acquiring/v1/transactions/${encodedId}:fastrefund`;
|
|
112
|
+
// Wire body — exactly the four fields per spec. `amount` is bigint and
|
|
113
|
+
// is handled by the shared bigint-safe stringify in IsvHttpClient.
|
|
114
|
+
const body = {
|
|
115
|
+
amount: input.amount,
|
|
116
|
+
sourceCode: input.sourceCode,
|
|
117
|
+
merchantTrns: input.merchantTrns,
|
|
118
|
+
idempotencyKey: input.idempotencyKey,
|
|
119
|
+
};
|
|
120
|
+
const raw = await this.client.request({
|
|
121
|
+
method: 'POST',
|
|
122
|
+
path,
|
|
123
|
+
body,
|
|
124
|
+
idempotencyKey: input.idempotencyKey,
|
|
125
|
+
idempotent: false,
|
|
126
|
+
endpoint: 'POST /acquiring/v1/transactions/{transactionId}:fastrefund',
|
|
127
|
+
});
|
|
128
|
+
const refundTxId = (raw.transactionId ?? raw.TransactionId ?? '');
|
|
129
|
+
const eventId = (raw.eventId ?? raw.EventId ?? 0);
|
|
130
|
+
const amount = (raw.amount ?? raw.Amount ?? 0);
|
|
131
|
+
return {
|
|
132
|
+
transactionId: refundTxId,
|
|
133
|
+
eventId,
|
|
134
|
+
amount,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=fast-refund-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fast-refund-client.js","sourceRoot":"","sources":["../../src/refunds/fast-refund-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAIH,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AA2DzD,8EAA8E;AAC9E,mBAAmB;AACnB,8EAA8E;AAE9E;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,OAAO,gBAAgB;IACV,MAAM,CAAgB;IAEvC,YAAY,MAA8B;QACxC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IAC9B,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,KAAK,CAAC,MAAM,CAAC,KAAwB;QACnC,kFAAkF;QAClF,IAAI,KAAK,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC;YACvB,MAAM,IAAI,mBAAmB,CAAC;gBAC5B,OAAO,EAAE,gEAAgE,KAAK,CAAC,MAAM,EAAE;aACxF,CAAC,CAAC;QACL,CAAC;QACD,IAAI,OAAO,KAAK,CAAC,UAAU,KAAK,QAAQ,IAAI,KAAK,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1E,MAAM,IAAI,mBAAmB,CAAC;gBAC5B,OAAO,EAAE,gEAAgE;aAC1E,CAAC,CAAC;QACL,CAAC;QACD,IAAI,OAAO,KAAK,CAAC,YAAY,KAAK,QAAQ,IAAI,KAAK,CAAC,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC9E,MAAM,IAAI,mBAAmB,CAAC;gBAC5B,OAAO,EAAE,kEAAkE;aAC5E,CAAC,CAAC;QACL,CAAC;QACD,IAAI,OAAO,KAAK,CAAC,cAAc,KAAK,QAAQ,IAAI,KAAK,CAAC,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAClF,MAAM,IAAI,mBAAmB,CAAC;gBAC5B,OAAO,EAAE,oEAAoE;aAC9E,CAAC,CAAC;QACL,CAAC;QACD,IAAI,OAAO,KAAK,CAAC,aAAa,KAAK,QAAQ,IAAI,KAAK,CAAC,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAChF,MAAM,IAAI,mBAAmB,CAAC;gBAC5B,OAAO,EAAE,mEAAmE;aAC7E,CAAC,CAAC;QACL,CAAC;QAED,wEAAwE;QACxE,uEAAuE;QACvE,qDAAqD;QACrD,MAAM,SAAS,GAAG,kBAAkB,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QAC1D,MAAM,IAAI,GAAG,8BAA8B,SAAS,aAAa,CAAC;QAElE,uEAAuE;QACvE,mEAAmE;QACnE,MAAM,IAAI,GAAG;YACX,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,cAAc,EAAE,KAAK,CAAC,cAAc;SACrC,CAAC;QAcF,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAgB;YACnD,MAAM,EAAE,MAAM;YACd,IAAI;YACJ,IAAI;YACJ,cAAc,EAAE,KAAK,CAAC,cAAc;YACpC,UAAU,EAAE,KAAK;YACjB,QAAQ,EAAE,4DAA4D;SACvE,CAAC,CAAC;QAEH,MAAM,UAAU,GAAG,CAAC,GAAG,CAAC,aAAa,IAAI,GAAG,CAAC,aAAa,IAAI,EAAE,CAAkB,CAAC;QACnF,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,OAAO,IAAI,CAAC,CAAW,CAAC;QAC5D,MAAM,MAAM,GAAG,CAAC,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,CAAW,CAAC;QAEzD,OAAO;YACL,aAAa,EAAE,UAAU;YACzB,OAAO;YACP,MAAM;SACP,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* viva-payments-core/refunds — barrel export.
|
|
3
|
+
*
|
|
4
|
+
* Subpath: `@sakeetech/viva-payments-core/refunds`
|
|
5
|
+
*
|
|
6
|
+
* Public surface:
|
|
7
|
+
* - {@link FastRefundClient} — OAuth2 acquiring-scopes wrapper for
|
|
8
|
+
* `POST /acquiring/v1/transactions/{transactionId}:fastrefund`.
|
|
9
|
+
* - {@link resolveRefundStrategy} — pure decision function for the
|
|
10
|
+
* `auto | fast | standard` strategy resolver consumed by adapters.
|
|
11
|
+
*
|
|
12
|
+
* @see docs/plans/multi-mode-v0.md §8.5a
|
|
13
|
+
* @see docs/ENDPOINTS.md §4
|
|
14
|
+
*/
|
|
15
|
+
export { FastRefundClient } from './fast-refund-client.js';
|
|
16
|
+
export type { FastRefundClientConfig, FastRefundRequest, FastRefundResponse, } from './fast-refund-client.js';
|
|
17
|
+
export { resolveRefundStrategy } from './strategy.js';
|
|
18
|
+
export type { RefundStrategy, RefundContext, RefundDecision } from './strategy.js';
|
|
19
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/refunds/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,YAAY,EACV,sBAAsB,EACtB,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACtD,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* viva-payments-core/refunds — barrel export.
|
|
3
|
+
*
|
|
4
|
+
* Subpath: `@sakeetech/viva-payments-core/refunds`
|
|
5
|
+
*
|
|
6
|
+
* Public surface:
|
|
7
|
+
* - {@link FastRefundClient} — OAuth2 acquiring-scopes wrapper for
|
|
8
|
+
* `POST /acquiring/v1/transactions/{transactionId}:fastrefund`.
|
|
9
|
+
* - {@link resolveRefundStrategy} — pure decision function for the
|
|
10
|
+
* `auto | fast | standard` strategy resolver consumed by adapters.
|
|
11
|
+
*
|
|
12
|
+
* @see docs/plans/multi-mode-v0.md §8.5a
|
|
13
|
+
* @see docs/ENDPOINTS.md §4
|
|
14
|
+
*/
|
|
15
|
+
export { FastRefundClient } from './fast-refund-client.js';
|
|
16
|
+
export { resolveRefundStrategy } from './strategy.js';
|
|
17
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/refunds/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAO3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* resolveRefundStrategy — pure decision function for refund routing.
|
|
3
|
+
*
|
|
4
|
+
* Given a configured strategy (`auto` | `fast` | `standard`) and a refund
|
|
5
|
+
* context (card scheme + card-present flag), returns a {@link RefundDecision}
|
|
6
|
+
* describing which refund path to take and why. The caller (adapter refund
|
|
7
|
+
* handler) is responsible for executing the chosen path and — when the
|
|
8
|
+
* strategy is `auto` and Fast Refund returns 403 — falling back to standard.
|
|
9
|
+
*
|
|
10
|
+
* This is deliberately a pure function with no I/O so it is trivial to unit
|
|
11
|
+
* test and reuse from any adapter.
|
|
12
|
+
*
|
|
13
|
+
* @see docs/ENDPOINTS.md §4 (Fast vs Standard matrix)
|
|
14
|
+
* @see docs/STATE-MACHINE.md §3.1 (card scheme detection from retrieveTransaction)
|
|
15
|
+
* @see docs/plans/multi-mode-v0.md §8.5a
|
|
16
|
+
* @see references/payment-api.yaml:9268 (eligibility: Visa / MC / Maestro)
|
|
17
|
+
*/
|
|
18
|
+
export type RefundStrategy = 'auto' | 'fast' | 'standard';
|
|
19
|
+
/**
|
|
20
|
+
* Refund context surfaced from the adapter refund handler.
|
|
21
|
+
*
|
|
22
|
+
* Populated from a prior `retrieveTransaction` call (for `cardType`) plus
|
|
23
|
+
* a flag from the originating payment session indicating whether the
|
|
24
|
+
* transaction was card-not-present (e-commerce / Smart Checkout) — which
|
|
25
|
+
* every plugin-initiated payment is.
|
|
26
|
+
*/
|
|
27
|
+
export interface RefundContext {
|
|
28
|
+
/**
|
|
29
|
+
* `cardType` field from {@link RetrieveTransactionResponse}. Viva returns
|
|
30
|
+
* PascalCase scheme names: `'Visa' | 'MasterCard' | 'Maestro' | 'Amex' | ...`.
|
|
31
|
+
* Undefined when Viva omits the field (some non-card payment types).
|
|
32
|
+
*
|
|
33
|
+
* @see docs/STATE-MACHINE.md §3.1
|
|
34
|
+
*/
|
|
35
|
+
cardType?: string;
|
|
36
|
+
/**
|
|
37
|
+
* Whether the original transaction was card-not-present (e-commerce).
|
|
38
|
+
* For plugin-initiated payments via Smart Checkout this is always `true`.
|
|
39
|
+
* Kept as an explicit input for future POS / in-store integrations where
|
|
40
|
+
* Fast Refund is not allowed.
|
|
41
|
+
*/
|
|
42
|
+
isCardNotPresent: boolean;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Decision returned by {@link resolveRefundStrategy}.
|
|
46
|
+
*
|
|
47
|
+
* `kind` selects the path; `reason` is a stable, machine-readable explanation
|
|
48
|
+
* suitable for structured logging and observability dashboards. The set of
|
|
49
|
+
* reason strings is a closed enum — extend only with explicit plan review.
|
|
50
|
+
*/
|
|
51
|
+
export type RefundDecision = {
|
|
52
|
+
kind: 'fast';
|
|
53
|
+
reason: 'configured' | 'auto-eligible';
|
|
54
|
+
} | {
|
|
55
|
+
kind: 'standard';
|
|
56
|
+
reason: 'configured' | 'auto-ineligible-scheme' | 'auto-ineligible-card-present' | 'auto-no-card-info';
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Pure decision function. Does not perform any I/O.
|
|
60
|
+
*
|
|
61
|
+
* Behaviour:
|
|
62
|
+
* - `strategy === 'fast'` → always `{ kind: 'fast', reason: 'configured' }`.
|
|
63
|
+
* Caller has explicitly opted in; eligibility is enforced server-side.
|
|
64
|
+
* - `strategy === 'standard'` → always `{ kind: 'standard', reason: 'configured' }`.
|
|
65
|
+
* - `strategy === 'auto'` → decided from {@link RefundContext}:
|
|
66
|
+
* - card-present → standard (`auto-ineligible-card-present`)
|
|
67
|
+
* - undefined cardType → standard (`auto-no-card-info`)
|
|
68
|
+
* - eligible scheme + CNP → fast (`auto-eligible`)
|
|
69
|
+
* - non-eligible scheme + CNP → standard (`auto-ineligible-scheme`)
|
|
70
|
+
*
|
|
71
|
+
* On Fast Refund 403 the caller should still fall back to standard refund —
|
|
72
|
+
* this function only handles the pre-call decision, not server-side rejection.
|
|
73
|
+
*
|
|
74
|
+
* @see docs/ENDPOINTS.md §4
|
|
75
|
+
* @see references/payment-api.yaml:9268
|
|
76
|
+
*/
|
|
77
|
+
export declare function resolveRefundStrategy(strategy: RefundStrategy, ctx: RefundContext): RefundDecision;
|
|
78
|
+
//# sourceMappingURL=strategy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"strategy.d.ts","sourceRoot":"","sources":["../../src/refunds/strategy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,MAAM,GAAG,UAAU,CAAC;AAmB1D;;;;;;;GAOG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;OAKG;IACH,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAED;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,YAAY,GAAG,eAAe,CAAA;CAAE,GACxD;IACE,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,EACF,YAAY,GACZ,wBAAwB,GACxB,8BAA8B,GAC9B,mBAAmB,CAAC;CACzB,CAAC;AAMN;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,cAAc,EACxB,GAAG,EAAE,aAAa,GACjB,cAAc,CAkBhB"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* resolveRefundStrategy — pure decision function for refund routing.
|
|
3
|
+
*
|
|
4
|
+
* Given a configured strategy (`auto` | `fast` | `standard`) and a refund
|
|
5
|
+
* context (card scheme + card-present flag), returns a {@link RefundDecision}
|
|
6
|
+
* describing which refund path to take and why. The caller (adapter refund
|
|
7
|
+
* handler) is responsible for executing the chosen path and — when the
|
|
8
|
+
* strategy is `auto` and Fast Refund returns 403 — falling back to standard.
|
|
9
|
+
*
|
|
10
|
+
* This is deliberately a pure function with no I/O so it is trivial to unit
|
|
11
|
+
* test and reuse from any adapter.
|
|
12
|
+
*
|
|
13
|
+
* @see docs/ENDPOINTS.md §4 (Fast vs Standard matrix)
|
|
14
|
+
* @see docs/STATE-MACHINE.md §3.1 (card scheme detection from retrieveTransaction)
|
|
15
|
+
* @see docs/plans/multi-mode-v0.md §8.5a
|
|
16
|
+
* @see references/payment-api.yaml:9268 (eligibility: Visa / MC / Maestro)
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Card schemes eligible for Fast Refund per Viva docs.
|
|
20
|
+
*
|
|
21
|
+
* Matched case-sensitively against `cardType` from `retrieveTransaction`
|
|
22
|
+
* (PascalCase per Viva convention). If Viva ever returns a differently-cased
|
|
23
|
+
* value, the decision falls through to the `auto-ineligible-scheme` branch
|
|
24
|
+
* and the caller routes to standard refund.
|
|
25
|
+
*
|
|
26
|
+
* @see references/payment-api.yaml:9268
|
|
27
|
+
* @see docs/STATE-MACHINE.md §3.1
|
|
28
|
+
*/
|
|
29
|
+
const FAST_REFUND_ELIGIBLE_SCHEMES = new Set([
|
|
30
|
+
'Visa',
|
|
31
|
+
'MasterCard',
|
|
32
|
+
'Maestro',
|
|
33
|
+
]);
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
// Decision function
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
/**
|
|
38
|
+
* Pure decision function. Does not perform any I/O.
|
|
39
|
+
*
|
|
40
|
+
* Behaviour:
|
|
41
|
+
* - `strategy === 'fast'` → always `{ kind: 'fast', reason: 'configured' }`.
|
|
42
|
+
* Caller has explicitly opted in; eligibility is enforced server-side.
|
|
43
|
+
* - `strategy === 'standard'` → always `{ kind: 'standard', reason: 'configured' }`.
|
|
44
|
+
* - `strategy === 'auto'` → decided from {@link RefundContext}:
|
|
45
|
+
* - card-present → standard (`auto-ineligible-card-present`)
|
|
46
|
+
* - undefined cardType → standard (`auto-no-card-info`)
|
|
47
|
+
* - eligible scheme + CNP → fast (`auto-eligible`)
|
|
48
|
+
* - non-eligible scheme + CNP → standard (`auto-ineligible-scheme`)
|
|
49
|
+
*
|
|
50
|
+
* On Fast Refund 403 the caller should still fall back to standard refund —
|
|
51
|
+
* this function only handles the pre-call decision, not server-side rejection.
|
|
52
|
+
*
|
|
53
|
+
* @see docs/ENDPOINTS.md §4
|
|
54
|
+
* @see references/payment-api.yaml:9268
|
|
55
|
+
*/
|
|
56
|
+
export function resolveRefundStrategy(strategy, ctx) {
|
|
57
|
+
if (strategy === 'fast') {
|
|
58
|
+
return { kind: 'fast', reason: 'configured' };
|
|
59
|
+
}
|
|
60
|
+
if (strategy === 'standard') {
|
|
61
|
+
return { kind: 'standard', reason: 'configured' };
|
|
62
|
+
}
|
|
63
|
+
// auto
|
|
64
|
+
if (!ctx.isCardNotPresent) {
|
|
65
|
+
return { kind: 'standard', reason: 'auto-ineligible-card-present' };
|
|
66
|
+
}
|
|
67
|
+
if (!ctx.cardType) {
|
|
68
|
+
return { kind: 'standard', reason: 'auto-no-card-info' };
|
|
69
|
+
}
|
|
70
|
+
if (FAST_REFUND_ELIGIBLE_SCHEMES.has(ctx.cardType)) {
|
|
71
|
+
return { kind: 'fast', reason: 'auto-eligible' };
|
|
72
|
+
}
|
|
73
|
+
return { kind: 'standard', reason: 'auto-ineligible-scheme' };
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=strategy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"strategy.js","sourceRoot":"","sources":["../../src/refunds/strategy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAQH;;;;;;;;;;GAUG;AACH,MAAM,4BAA4B,GAAwB,IAAI,GAAG,CAAC;IAChE,MAAM;IACN,YAAY;IACZ,SAAS;CACV,CAAC,CAAC;AA8CH,8EAA8E;AAC9E,oBAAoB;AACpB,8EAA8E;AAE9E;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,qBAAqB,CACnC,QAAwB,EACxB,GAAkB;IAElB,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;QACxB,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC;IAChD,CAAC;IACD,IAAI,QAAQ,KAAK,UAAU,EAAE,CAAC;QAC5B,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC;IACpD,CAAC;IACD,OAAO;IACP,IAAI,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;QAC1B,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,8BAA8B,EAAE,CAAC;IACtE,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;QAClB,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC;IAC3D,CAAC;IACD,IAAI,4BAA4B,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QACnD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC;IACnD,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,wBAAwB,EAAE,CAAC;AAChE,CAAC"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authentication types for the Viva Wallet ISV OAuth 2.0 and reseller
|
|
3
|
+
* basic-auth flows.
|
|
4
|
+
*
|
|
5
|
+
* Implementations live in S2 (packages/viva-payments-core/src/auth/).
|
|
6
|
+
* This file declares interfaces and response shapes only — no runtime code.
|
|
7
|
+
*
|
|
8
|
+
* @see references/viva-docs/md/oauth2-authentication.txt:179
|
|
9
|
+
* @see references/viva-docs/md/isv-credentials.txt:107
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Raw token response from `POST /connect/token` (client_credentials grant).
|
|
13
|
+
*
|
|
14
|
+
* Each token lasts for 3600 seconds (one hour). The `scope` field reflects
|
|
15
|
+
* the scopes granted to the ISV client application.
|
|
16
|
+
*
|
|
17
|
+
* @see references/viva-docs/md/oauth2-authentication.txt:179
|
|
18
|
+
*/
|
|
19
|
+
export interface OAuth2TokenResponse {
|
|
20
|
+
/** JWT bearer token. Include as `Authorization: Bearer <access_token>`. */
|
|
21
|
+
readonly access_token: string;
|
|
22
|
+
/** Lifetime in seconds. Typically 3600. */
|
|
23
|
+
readonly expires_in: number;
|
|
24
|
+
/** Always `"Bearer"` for this grant type. */
|
|
25
|
+
readonly token_type: 'Bearer';
|
|
26
|
+
/** Space-delimited scopes granted. */
|
|
27
|
+
readonly scope: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Enriched token value stored in the cache after a successful fetch.
|
|
31
|
+
* `expires_at` is `Date.now() + (expires_in * 1000)` at fetch time.
|
|
32
|
+
*/
|
|
33
|
+
export interface CachedToken {
|
|
34
|
+
readonly access_token: string;
|
|
35
|
+
/** Unix epoch milliseconds when the token expires. */
|
|
36
|
+
readonly expires_at: number;
|
|
37
|
+
readonly scope: string;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Credentials for the ISV Reseller basic-auth strategy.
|
|
41
|
+
*
|
|
42
|
+
* Some ISV API calls (e.g. cancelOrder) require Reseller-level credentials
|
|
43
|
+
* rather than the OAuth2 bearer token. These are distinct from the
|
|
44
|
+
* Client ID + Client Secret used for client_credentials.
|
|
45
|
+
*
|
|
46
|
+
* @see references/viva-docs/md/isv-credentials.txt:107
|
|
47
|
+
*/
|
|
48
|
+
export interface ResellerBasicAuthCredentials {
|
|
49
|
+
/** ISV Partner Reseller ID provided by Viva. */
|
|
50
|
+
readonly resellerId: string;
|
|
51
|
+
/** Target merchant's Merchant ID. */
|
|
52
|
+
readonly merchantId: string;
|
|
53
|
+
/** ISV Partner Reseller API Key provided by Viva. */
|
|
54
|
+
readonly resellerApiKey: string;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Pluggable authentication strategy interface.
|
|
58
|
+
*
|
|
59
|
+
* Implementations (OAuth2ClientCredentialsStrategy, ResellerBasicAuthStrategy)
|
|
60
|
+
* are defined in S2. The HTTP client accepts an `AuthStrategy` and calls
|
|
61
|
+
* `getBearerToken()` before each outbound request.
|
|
62
|
+
*
|
|
63
|
+
* Single-flight token refresh and caching are implementation concerns;
|
|
64
|
+
* callers only invoke `getBearerToken()`.
|
|
65
|
+
*
|
|
66
|
+
* @see references/viva-docs/md/oauth2-authentication.txt:128
|
|
67
|
+
*/
|
|
68
|
+
export interface AuthStrategy {
|
|
69
|
+
/**
|
|
70
|
+
* Returns a valid bearer token string (without the `Bearer ` prefix).
|
|
71
|
+
*
|
|
72
|
+
* @param opts.forceRefresh - If true, bypass the cache and fetch a fresh token.
|
|
73
|
+
*/
|
|
74
|
+
getBearerToken(opts?: {
|
|
75
|
+
readonly forceRefresh?: boolean;
|
|
76
|
+
}): Promise<string>;
|
|
77
|
+
/** Stable name used in logs and metrics (e.g. `"oauth2"`, `"reseller"`). */
|
|
78
|
+
readonly name: string;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/types/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH;;;;;;;GAOG;AACH,MAAM,WAAW,mBAAmB;IAClC,2EAA2E;IAC3E,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,2CAA2C;IAC3C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,6CAA6C;IAC7C,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC;IAC9B,sCAAsC;IACtC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,sDAAsD;IACtD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAMD;;;;;;;;GAQG;AACH,MAAM,WAAW,4BAA4B;IAC3C,gDAAgD;IAChD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,qCAAqC;IACrC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,qDAAqD;IACrD,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC;AAMD;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;OAIG;IACH,cAAc,CAAC,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAE5E,4EAA4E;IAC5E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authentication types for the Viva Wallet ISV OAuth 2.0 and reseller
|
|
3
|
+
* basic-auth flows.
|
|
4
|
+
*
|
|
5
|
+
* Implementations live in S2 (packages/viva-payments-core/src/auth/).
|
|
6
|
+
* This file declares interfaces and response shapes only — no runtime code.
|
|
7
|
+
*
|
|
8
|
+
* @see references/viva-docs/md/oauth2-authentication.txt:179
|
|
9
|
+
* @see references/viva-docs/md/isv-credentials.txt:107
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/types/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Viva's numeric CardTypeId → string scheme name mapping.
|
|
3
|
+
*
|
|
4
|
+
* Used by `Payments.retrieveTransaction` to populate the normalized
|
|
5
|
+
* `cardType: string` field for downstream consumers (e.g.,
|
|
6
|
+
* {@link import('../refunds/strategy.js').resolveRefundStrategy resolveRefundStrategy}).
|
|
7
|
+
*
|
|
8
|
+
* Mapping source: `references/viva-docs/md/wh-transaction-payment-created.txt`
|
|
9
|
+
* (search for `CardTypeId`). Viva documents the following nine values:
|
|
10
|
+
*
|
|
11
|
+
* 0 = Visa
|
|
12
|
+
* 1 = Mastercard
|
|
13
|
+
* 2 = Diners
|
|
14
|
+
* 3 = Amex
|
|
15
|
+
* 4 = Invalid
|
|
16
|
+
* 5 = Unknown
|
|
17
|
+
* 6 = Maestro
|
|
18
|
+
* 7 = Discover
|
|
19
|
+
* 8 = JCB
|
|
20
|
+
*
|
|
21
|
+
* Casing note:
|
|
22
|
+
* `resolveRefundStrategy` matches the Fast-Refund eligible-scheme set
|
|
23
|
+
* case-sensitively against the string emitted here. The strategy's set
|
|
24
|
+
* uses `'MasterCard'` (camelCase). We emit `'MasterCard'` for cardTypeId
|
|
25
|
+
* `1` to match — this is the only difference from the doc's raw casing.
|
|
26
|
+
* Diners is emitted as the doc's `'Diners'` (no "Club") so future
|
|
27
|
+
* eligibility additions key off a single canonical string.
|
|
28
|
+
*
|
|
29
|
+
* The sentinel categories `Invalid` (4) and `Unknown` (5) are intentionally
|
|
30
|
+
* NOT exposed as scheme strings — they indicate "no useful card info" and
|
|
31
|
+
* `resolveCardType` returns `undefined` for them so the auto-refund
|
|
32
|
+
* decision falls through to `auto-no-card-info`.
|
|
33
|
+
*
|
|
34
|
+
* @see references/viva-docs/md/wh-transaction-payment-created.txt — search "CardTypeId"
|
|
35
|
+
* @see ../refunds/strategy.ts (FAST_REFUND_ELIGIBLE_SCHEMES)
|
|
36
|
+
* @see docs/STATE-MACHINE.md §3.1
|
|
37
|
+
*/
|
|
38
|
+
export declare const CARD_TYPE_BY_ID: Readonly<Record<number, string>>;
|
|
39
|
+
/**
|
|
40
|
+
* Pure helper — returns the string scheme name for a Viva numeric cardTypeId,
|
|
41
|
+
* or `undefined` if the id is null/undefined, a known sentinel (Invalid /
|
|
42
|
+
* Unknown), or not present in the documented mapping.
|
|
43
|
+
*
|
|
44
|
+
* Pure, no I/O. Safe to call from anywhere — including refund strategy
|
|
45
|
+
* decisions and tests.
|
|
46
|
+
*/
|
|
47
|
+
export declare function resolveCardType(cardTypeId: number | null | undefined): string | undefined;
|
|
48
|
+
//# sourceMappingURL=card-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"card-types.d.ts","sourceRoot":"","sources":["../../src/types/card-types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,eAAO,MAAM,eAAe,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAU3D,CAAC;AAEH;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACpC,MAAM,GAAG,SAAS,CAGpB"}
|