@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.
Files changed (203) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +413 -0
  3. package/dist/auth/http.d.ts +44 -0
  4. package/dist/auth/http.d.ts.map +1 -0
  5. package/dist/auth/http.js +80 -0
  6. package/dist/auth/http.js.map +1 -0
  7. package/dist/auth/index.d.ts +19 -0
  8. package/dist/auth/index.d.ts.map +1 -0
  9. package/dist/auth/index.js +18 -0
  10. package/dist/auth/index.js.map +1 -0
  11. package/dist/auth/oauth2-strategy.d.ts +117 -0
  12. package/dist/auth/oauth2-strategy.d.ts.map +1 -0
  13. package/dist/auth/oauth2-strategy.js +217 -0
  14. package/dist/auth/oauth2-strategy.js.map +1 -0
  15. package/dist/auth/reseller-strategy.d.ts +65 -0
  16. package/dist/auth/reseller-strategy.d.ts.map +1 -0
  17. package/dist/auth/reseller-strategy.js +68 -0
  18. package/dist/auth/reseller-strategy.js.map +1 -0
  19. package/dist/auth/single-flight.d.ts +81 -0
  20. package/dist/auth/single-flight.d.ts.map +1 -0
  21. package/dist/auth/single-flight.js +160 -0
  22. package/dist/auth/single-flight.js.map +1 -0
  23. package/dist/auth/token-cache.d.ts +50 -0
  24. package/dist/auth/token-cache.d.ts.map +1 -0
  25. package/dist/auth/token-cache.js +59 -0
  26. package/dist/auth/token-cache.js.map +1 -0
  27. package/dist/errors/api-error.d.ts +15 -0
  28. package/dist/errors/api-error.d.ts.map +1 -0
  29. package/dist/errors/api-error.js +18 -0
  30. package/dist/errors/api-error.js.map +1 -0
  31. package/dist/errors/auth-error.d.ts +14 -0
  32. package/dist/errors/auth-error.d.ts.map +1 -0
  33. package/dist/errors/auth-error.js +17 -0
  34. package/dist/errors/auth-error.js.map +1 -0
  35. package/dist/errors/base.d.ts +59 -0
  36. package/dist/errors/base.d.ts.map +1 -0
  37. package/dist/errors/base.js +51 -0
  38. package/dist/errors/base.js.map +1 -0
  39. package/dist/errors/index.d.ts +18 -0
  40. package/dist/errors/index.d.ts.map +1 -0
  41. package/dist/errors/index.js +16 -0
  42. package/dist/errors/index.js.map +1 -0
  43. package/dist/errors/mode-mismatch-error.d.ts +19 -0
  44. package/dist/errors/mode-mismatch-error.d.ts.map +1 -0
  45. package/dist/errors/mode-mismatch-error.js +22 -0
  46. package/dist/errors/mode-mismatch-error.js.map +1 -0
  47. package/dist/errors/rate-limit-error.d.ts +20 -0
  48. package/dist/errors/rate-limit-error.d.ts.map +1 -0
  49. package/dist/errors/rate-limit-error.js +20 -0
  50. package/dist/errors/rate-limit-error.js.map +1 -0
  51. package/dist/errors/validation-error.d.ts +14 -0
  52. package/dist/errors/validation-error.d.ts.map +1 -0
  53. package/dist/errors/validation-error.js +17 -0
  54. package/dist/errors/validation-error.js.map +1 -0
  55. package/dist/errors/webhook-error.d.ts +14 -0
  56. package/dist/errors/webhook-error.d.ts.map +1 -0
  57. package/dist/errors/webhook-error.js +17 -0
  58. package/dist/errors/webhook-error.js.map +1 -0
  59. package/dist/index.d.ts +15 -0
  60. package/dist/index.d.ts.map +1 -0
  61. package/dist/index.js +15 -0
  62. package/dist/index.js.map +1 -0
  63. package/dist/isv/accounts.d.ts +38 -0
  64. package/dist/isv/accounts.d.ts.map +1 -0
  65. package/dist/isv/accounts.js +60 -0
  66. package/dist/isv/accounts.js.map +1 -0
  67. package/dist/isv/client.d.ts +187 -0
  68. package/dist/isv/client.d.ts.map +1 -0
  69. package/dist/isv/client.js +465 -0
  70. package/dist/isv/client.js.map +1 -0
  71. package/dist/isv/index.d.ts +52 -0
  72. package/dist/isv/index.d.ts.map +1 -0
  73. package/dist/isv/index.js +53 -0
  74. package/dist/isv/index.js.map +1 -0
  75. package/dist/isv/legacy-basic-client.d.ts +122 -0
  76. package/dist/isv/legacy-basic-client.d.ts.map +1 -0
  77. package/dist/isv/legacy-basic-client.js +281 -0
  78. package/dist/isv/legacy-basic-client.js.map +1 -0
  79. package/dist/isv/payments.d.ts +199 -0
  80. package/dist/isv/payments.d.ts.map +1 -0
  81. package/dist/isv/payments.js +385 -0
  82. package/dist/isv/payments.js.map +1 -0
  83. package/dist/isv/sources.d.ts +80 -0
  84. package/dist/isv/sources.d.ts.map +1 -0
  85. package/dist/isv/sources.js +112 -0
  86. package/dist/isv/sources.js.map +1 -0
  87. package/dist/isv/webhooks-api.d.ts +48 -0
  88. package/dist/isv/webhooks-api.d.ts.map +1 -0
  89. package/dist/isv/webhooks-api.js +66 -0
  90. package/dist/isv/webhooks-api.js.map +1 -0
  91. package/dist/legacy/client.d.ts +199 -0
  92. package/dist/legacy/client.d.ts.map +1 -0
  93. package/dist/legacy/client.js +351 -0
  94. package/dist/legacy/client.js.map +1 -0
  95. package/dist/legacy/index.d.ts +15 -0
  96. package/dist/legacy/index.d.ts.map +1 -0
  97. package/dist/legacy/index.js +14 -0
  98. package/dist/legacy/index.js.map +1 -0
  99. package/dist/observability/context.d.ts +30 -0
  100. package/dist/observability/context.d.ts.map +1 -0
  101. package/dist/observability/context.js +40 -0
  102. package/dist/observability/context.js.map +1 -0
  103. package/dist/observability/index.d.ts +15 -0
  104. package/dist/observability/index.d.ts.map +1 -0
  105. package/dist/observability/index.js +11 -0
  106. package/dist/observability/index.js.map +1 -0
  107. package/dist/observability/logger.d.ts +81 -0
  108. package/dist/observability/logger.d.ts.map +1 -0
  109. package/dist/observability/logger.js +127 -0
  110. package/dist/observability/logger.js.map +1 -0
  111. package/dist/observability/metrics.d.ts +37 -0
  112. package/dist/observability/metrics.d.ts.map +1 -0
  113. package/dist/observability/metrics.js +40 -0
  114. package/dist/observability/metrics.js.map +1 -0
  115. package/dist/observability/redact.d.ts +21 -0
  116. package/dist/observability/redact.d.ts.map +1 -0
  117. package/dist/observability/redact.js +72 -0
  118. package/dist/observability/redact.js.map +1 -0
  119. package/dist/observability/tracer.d.ts +25 -0
  120. package/dist/observability/tracer.d.ts.map +1 -0
  121. package/dist/observability/tracer.js +18 -0
  122. package/dist/observability/tracer.js.map +1 -0
  123. package/dist/payments/client.d.ts +247 -0
  124. package/dist/payments/client.d.ts.map +1 -0
  125. package/dist/payments/client.js +488 -0
  126. package/dist/payments/client.js.map +1 -0
  127. package/dist/payments/index.d.ts +14 -0
  128. package/dist/payments/index.d.ts.map +1 -0
  129. package/dist/payments/index.js +13 -0
  130. package/dist/payments/index.js.map +1 -0
  131. package/dist/refunds/fast-refund-client.d.ts +128 -0
  132. package/dist/refunds/fast-refund-client.d.ts.map +1 -0
  133. package/dist/refunds/fast-refund-client.js +138 -0
  134. package/dist/refunds/fast-refund-client.js.map +1 -0
  135. package/dist/refunds/index.d.ts +19 -0
  136. package/dist/refunds/index.d.ts.map +1 -0
  137. package/dist/refunds/index.js +17 -0
  138. package/dist/refunds/index.js.map +1 -0
  139. package/dist/refunds/strategy.d.ts +78 -0
  140. package/dist/refunds/strategy.d.ts.map +1 -0
  141. package/dist/refunds/strategy.js +75 -0
  142. package/dist/refunds/strategy.js.map +1 -0
  143. package/dist/types/auth.d.ts +80 -0
  144. package/dist/types/auth.d.ts.map +1 -0
  145. package/dist/types/auth.js +12 -0
  146. package/dist/types/auth.js.map +1 -0
  147. package/dist/types/card-types.d.ts +48 -0
  148. package/dist/types/card-types.d.ts.map +1 -0
  149. package/dist/types/card-types.js +62 -0
  150. package/dist/types/card-types.js.map +1 -0
  151. package/dist/types/common.d.ts +160 -0
  152. package/dist/types/common.d.ts.map +1 -0
  153. package/dist/types/common.js +70 -0
  154. package/dist/types/common.js.map +1 -0
  155. package/dist/types/index.d.ts +21 -0
  156. package/dist/types/index.d.ts.map +1 -0
  157. package/dist/types/index.js +21 -0
  158. package/dist/types/index.js.map +1 -0
  159. package/dist/types/isv-accounts.d.ts +109 -0
  160. package/dist/types/isv-accounts.d.ts.map +1 -0
  161. package/dist/types/isv-accounts.js +22 -0
  162. package/dist/types/isv-accounts.js.map +1 -0
  163. package/dist/types/isv-payments.d.ts +262 -0
  164. package/dist/types/isv-payments.d.ts.map +1 -0
  165. package/dist/types/isv-payments.js +19 -0
  166. package/dist/types/isv-payments.js.map +1 -0
  167. package/dist/types/status.d.ts +125 -0
  168. package/dist/types/status.d.ts.map +1 -0
  169. package/dist/types/status.js +19 -0
  170. package/dist/types/status.js.map +1 -0
  171. package/dist/types/webhook-events.d.ts +447 -0
  172. package/dist/types/webhook-events.d.ts.map +1 -0
  173. package/dist/types/webhook-events.js +76 -0
  174. package/dist/types/webhook-events.js.map +1 -0
  175. package/dist/webhooks/challenge-response.d.ts +28 -0
  176. package/dist/webhooks/challenge-response.d.ts.map +1 -0
  177. package/dist/webhooks/challenge-response.js +35 -0
  178. package/dist/webhooks/challenge-response.js.map +1 -0
  179. package/dist/webhooks/event-types.d.ts +44 -0
  180. package/dist/webhooks/event-types.d.ts.map +1 -0
  181. package/dist/webhooks/event-types.js +50 -0
  182. package/dist/webhooks/event-types.js.map +1 -0
  183. package/dist/webhooks/extract-client-ip.d.ts +40 -0
  184. package/dist/webhooks/extract-client-ip.d.ts.map +1 -0
  185. package/dist/webhooks/extract-client-ip.js +72 -0
  186. package/dist/webhooks/extract-client-ip.js.map +1 -0
  187. package/dist/webhooks/hmac-verify.d.ts +38 -0
  188. package/dist/webhooks/hmac-verify.d.ts.map +1 -0
  189. package/dist/webhooks/hmac-verify.js +92 -0
  190. package/dist/webhooks/hmac-verify.js.map +1 -0
  191. package/dist/webhooks/index.d.ts +19 -0
  192. package/dist/webhooks/index.d.ts.map +1 -0
  193. package/dist/webhooks/index.js +19 -0
  194. package/dist/webhooks/index.js.map +1 -0
  195. package/dist/webhooks/ip-allowlist.d.ts +59 -0
  196. package/dist/webhooks/ip-allowlist.d.ts.map +1 -0
  197. package/dist/webhooks/ip-allowlist.js +147 -0
  198. package/dist/webhooks/ip-allowlist.js.map +1 -0
  199. package/dist/webhooks/status-lattice.d.ts +72 -0
  200. package/dist/webhooks/status-lattice.d.ts.map +1 -0
  201. package/dist/webhooks/status-lattice.js +208 -0
  202. package/dist/webhooks/status-lattice.js.map +1 -0
  203. package/package.json +85 -0
@@ -0,0 +1,385 @@
1
+ /**
2
+ * IsvPayments — ISV Payment API methods.
3
+ *
4
+ * Covers:
5
+ * - createOrder → POST /checkout/v2/orders?merchantId={merchantId} (OAuth2)
6
+ * - retrieveTransaction → GET /checkout/v2/transactions/{transactionId} (OAuth2)
7
+ * - refundPayment → POST /api/transactions/{transactionId} (Legacy/Basic)
8
+ * - cancelOrder → DELETE /checkout/v2/orders/{orderCode} (OAuth2)
9
+ *
10
+ * All methods validate inputs locally before making HTTP calls.
11
+ * Amounts are in integer minor units (bigint) per plan P15.
12
+ *
13
+ * Idempotency: createOrder and refundPayment are non-idempotent (idempotent: false).
14
+ * retrieveTransaction and cancelOrder are idempotent.
15
+ *
16
+ * --- Refund path (F1 — probe-verified 2026-04-25) ---
17
+ * Viva returns 405 on `POST /checkout/v2/transactions/{id}` (v2/OAuth2 path).
18
+ * The ONLY working refund path is `POST /api/transactions/{transactionId}` on the
19
+ * LEGACY HOST (`demo.vivapayments.com` / `www.vivapayments.com`) with Basic auth
20
+ * (MerchantId + ApiKey). The 401-fallback design is NOT applicable here — Viva
21
+ * returns 405 (not 401) on the v2 path, so no fallback would ever trigger.
22
+ * refundPayment now calls `legacyClient` DIRECTLY without any v2 attempt.
23
+ *
24
+ * @see references/viva-docs/md/tut-create-recurring-payment.txt:288 (legacy refund endpoint)
25
+ *
26
+ * --- retrieveTransaction / cancelOrder fallback (D15 — kept defensive) ---
27
+ * The optional `secondaryClient` is a fallback for retrieveTransaction and
28
+ * cancelOrder. When the primary OAuth2 client returns 401 (after force-refresh),
29
+ * the call retries once with the secondary client. A 401 from secondary surfaces
30
+ * as VivaAuthError — no further retry.
31
+ * Note: cancelOrder is unverified against live sandbox as of 2026-04-25 probe;
32
+ * kept on OAuth2 + 401-fallback path defensively.
33
+ *
34
+ * --- Idempotency-Key header (F2 — probe-verified 2026-04-25) ---
35
+ * The `Idempotency-Key` header is sent on createOrder but Viva does NOT appear
36
+ * to deduplicate server-side (same key returned two different orderCodes in probe).
37
+ * Local dedup via `viva_transaction` row is the authoritative dedup mechanism.
38
+ * Header is retained for forward-compat (zero cost, may be honoured in future).
39
+ *
40
+ * @see references/viva-docs/md/payment-isv-api.txt:1
41
+ * @see references/viva-docs/md/webhooks-for-payments.txt:248 (retrieve before update)
42
+ * @see references/viva-docs/md/isv-partner-program.txt:104 (ISV overview)
43
+ * @see references/viva-docs/md/isv-credentials.txt:107 (reseller credentials)
44
+ * @see docs/plans/vendure-plugin-v0.md §D15 (reseller fallback scope)
45
+ */
46
+ import { VivaValidationError, VivaAuthError } from '../errors/index.js';
47
+ // ---------------------------------------------------------------------------
48
+ // Validation helpers
49
+ // ---------------------------------------------------------------------------
50
+ /**
51
+ * Validates an ISO 4217 numeric currency code (3-digit numeric string).
52
+ *
53
+ * Per plan P15: currencyCode must be a valid 3-digit numeric string.
54
+ * Examples: '978' (EUR), '826' (GBP), '840' (USD).
55
+ *
56
+ * @see references/viva-docs/md/webhooks-for-payments.txt:487
57
+ */
58
+ function isValidCurrencyCode(code) {
59
+ return /^\d{3}$/.test(code);
60
+ }
61
+ // ---------------------------------------------------------------------------
62
+ // IsvPayments
63
+ // ---------------------------------------------------------------------------
64
+ /**
65
+ * ISV Payment API client.
66
+ *
67
+ * Constructed with an IsvHttpClient instance shared across all ISV modules.
68
+ * Each method scopes its request to a specific merchant via the merchantId
69
+ * query parameter per the ISV integration model.
70
+ *
71
+ * - `client`: primary OAuth2 client for createOrder, retrieveTransaction, cancelOrder.
72
+ * - `secondaryClient`: optional 401-fallback for retrieveTransaction and cancelOrder.
73
+ * When undefined, 401 errors propagate normally.
74
+ * - `legacyClient`: REQUIRED for refundPayment. Calls `POST /api/transactions/{id}`
75
+ * on the legacy host with Basic auth (MerchantId + ApiKey). If absent, refundPayment
76
+ * throws `VIVA_REFUND_REJECTED` with a config-missing message.
77
+ *
78
+ * Probe-verified 2026-04-25: refund MUST go through legacy client — v2/OAuth2 path
79
+ * returns 405. cancelOrder is unverified but kept on v2/OAuth2 + 401-fallback defensively.
80
+ *
81
+ * @see references/viva-docs/md/tut-create-recurring-payment.txt:288 (legacy refund path)
82
+ * @see references/viva-docs/md/payment-isv-api.txt:1
83
+ * @see references/viva-docs/md/isv-partner-program.txt:61 (P1: merchant scoping)
84
+ * @see references/viva-docs/md/isv-credentials.txt:107 (reseller credentials)
85
+ * @see docs/plans/vendure-plugin-v0.md §D15 (reseller fallback)
86
+ */
87
+ export class IsvPayments {
88
+ client;
89
+ secondaryClient;
90
+ legacyClient;
91
+ constructor(client, secondaryClient, legacyClient) {
92
+ this.client = client;
93
+ this.secondaryClient = secondaryClient;
94
+ this.legacyClient = legacyClient;
95
+ }
96
+ /**
97
+ * Create a payment order for a specific ISV merchant.
98
+ *
99
+ * Sends a POST /checkout/v2/orders?merchantId={merchantId} request.
100
+ * The `Idempotency-Key` header is sent on every call but Viva does NOT appear
101
+ * to deduplicate server-side as of 2026-04-25 (probe: same key → two different
102
+ * orderCodes). Local dedup via `viva_transaction` row is the authoritative
103
+ * dedup mechanism. Header retained for forward-compat only.
104
+ *
105
+ * Input validation (throws VivaValidationError before HTTP call):
106
+ * - amountMinor must be > 0 (per plan P15)
107
+ * - currencyCode must be a valid 3-digit numeric string (per plan P15)
108
+ *
109
+ * Non-idempotent: does not retry on 4xx/5xx (only connection-level errors).
110
+ *
111
+ * @see references/viva-docs/md/payment-isv-api.txt:1
112
+ * @see references/viva-docs/md/isv-partner-program.txt:61 (P14 idempotency)
113
+ * @see references/viva-docs/md/isv-partner-program.txt:83 (P15 amounts)
114
+ */
115
+ async createOrder(req, opts) {
116
+ // Local validation per P14 and P15
117
+ if (req.amount <= 0n) {
118
+ throw new VivaValidationError({
119
+ message: `createOrder: amountMinor must be > 0, got ${req.amount}`,
120
+ });
121
+ }
122
+ if (!isValidCurrencyCode(req.currencyCode)) {
123
+ throw new VivaValidationError({
124
+ message: `createOrder: currencyCode must be a 3-digit numeric string (ISO 4217), got "${req.currencyCode}"`,
125
+ });
126
+ }
127
+ // Build wire body: convert bigint amount to number for JSON.
128
+ // Amount in minor units is always within safe integer range for real payments.
129
+ const wireBody = {
130
+ amount: req.amount, // bigintSafeStringify in client handles this
131
+ currencyCode: Number(req.currencyCode), // Viva expects numeric currency code as number
132
+ };
133
+ if (req.merchantTrns !== undefined)
134
+ wireBody['merchantTrns'] = req.merchantTrns;
135
+ if (req.customerTrns !== undefined)
136
+ wireBody['customerTrns'] = req.customerTrns;
137
+ if (req.customerEmail !== undefined)
138
+ wireBody['email'] = req.customerEmail;
139
+ if (req.customerPhone !== undefined)
140
+ wireBody['phone'] = req.customerPhone;
141
+ if (req.customerFullName !== undefined)
142
+ wireBody['fullName'] = req.customerFullName;
143
+ if (req.successUrl !== undefined)
144
+ wireBody['successUrl'] = req.successUrl;
145
+ if (req.failureUrl !== undefined)
146
+ wireBody['failureUrl'] = req.failureUrl;
147
+ if (req.tags !== undefined)
148
+ wireBody['tags'] = req.tags;
149
+ if (req.sourceCode !== undefined)
150
+ wireBody['sourceCode'] = req.sourceCode;
151
+ if (req.paymentTimeoutSeconds !== undefined)
152
+ wireBody['paymentTimeout'] = req.paymentTimeoutSeconds;
153
+ if (req.preselectedPaymentMethod !== undefined)
154
+ wireBody['preselectedPaymentMethod'] = req.preselectedPaymentMethod;
155
+ const raw = await this.client.request({
156
+ method: 'POST',
157
+ path: '/checkout/v2/orders',
158
+ query: { merchantId: opts.merchantId },
159
+ body: wireBody,
160
+ idempotencyKey: opts.idempotencyKey,
161
+ idempotent: false, // per plan Auth Flow line 319
162
+ endpoint: 'POST /checkout/v2/orders',
163
+ });
164
+ return { orderCode: raw.OrderCode };
165
+ }
166
+ /**
167
+ * Retrieve transaction details for a specific ISV merchant transaction.
168
+ *
169
+ * Per Viva docs, this SHOULD be called before updating any local transaction
170
+ * status on receipt of a webhook. Validates orderCode and statusId from Viva.
171
+ *
172
+ * Idempotent: safe to retry on 429 and 5xx.
173
+ *
174
+ * Path + auth verified 2026-04-25 (F3):
175
+ * `GET /checkout/v2/transactions/{transactionId}` with OAuth2 Bearer → correct.
176
+ * 404 error envelope shape: `{"status": 404, "message": null, "eventId": "0"}`.
177
+ * Note: `message` can be null — handle defensively.
178
+ *
179
+ * 401 → reseller fallback (D15) — kept DEFENSIVE:
180
+ * If the primary OAuth2 client receives a 401 and secondaryClient is configured,
181
+ * the request is retried once with the secondary (Reseller basic-auth) client.
182
+ * A 401 from the secondary surfaces immediately as VivaAuthError — no further retry.
183
+ * The primary path is verified working; fallback is defensive for edge-case tenants.
184
+ *
185
+ * @see references/viva-docs/md/webhooks-for-payments.txt:248 (retrieve before update)
186
+ * @see references/viva-docs/md/payment-isv-api.txt:1
187
+ * @see references/viva-docs/md/isv-credentials.txt:107 (reseller basic-auth)
188
+ * @see docs/plans/vendure-plugin-v0.md §D15 (reseller fallback scope)
189
+ */
190
+ async retrieveTransaction(transactionId, opts = {}) {
191
+ const query = {};
192
+ if (opts.merchantId)
193
+ query['merchantId'] = opts.merchantId;
194
+ const requestOpts = {
195
+ method: 'GET',
196
+ path: `/checkout/v2/transactions/${transactionId}`,
197
+ query,
198
+ idempotent: true,
199
+ endpoint: 'GET /checkout/v2/transactions/{transactionId}',
200
+ };
201
+ // Viva API returns PascalCase field names (e.g. OrderCode, StatusId).
202
+ // We normalize to camelCase matching RetrieveTransactionResponse.
203
+ // The bigint-safe parser in IsvHttpClient already converts OrderCode to bigint.
204
+ let raw;
205
+ try {
206
+ raw = await this.client.request(requestOpts);
207
+ }
208
+ catch (err) {
209
+ // 401 → reseller fallback (D15). Only attempt if secondaryClient is present.
210
+ // A 401 from the secondary surfaces immediately — no further retry.
211
+ // @see docs/plans/vendure-plugin-v0.md §D15
212
+ // @see references/viva-docs/md/isv-credentials.txt:107
213
+ if (err instanceof VivaAuthError && err.httpStatus === 401 && this.secondaryClient) {
214
+ raw = await this.secondaryClient.request(requestOpts);
215
+ }
216
+ else {
217
+ throw err;
218
+ }
219
+ }
220
+ // Normalize: accept both PascalCase (wire) and camelCase (normalized) field names.
221
+ // @see references/viva-docs/md/account-api.txt:1584 (OrderCode: long)
222
+ const orderCode = (raw['orderCode'] ?? raw['OrderCode']);
223
+ const cardNumber = raw['cardNumber'] ?? raw['CardNumber'];
224
+ const cardTypeId = raw['cardTypeId'] ?? raw['CardTypeId'];
225
+ const email = raw['email'] ?? raw['Email'];
226
+ const fullName = raw['fullName'] ?? raw['FullName'];
227
+ const merchantTrns = raw['merchantTrns'] ?? raw['MerchantTrns'];
228
+ const customerTrns = raw['customerTrns'] ?? raw['CustomerTrns'];
229
+ const connectedAccountId = raw['connectedAccountId'] ?? raw['ConnectedAccountId'];
230
+ // Build with conditional optional fields to satisfy exactOptionalPropertyTypes.
231
+ // (Cannot assign to readonly Partial<> properties so we use spread.)
232
+ return {
233
+ transactionId: (raw['transactionId'] ?? raw['TransactionId']),
234
+ orderCode,
235
+ statusId: (raw['statusId'] ?? raw['StatusId']),
236
+ amount: BigInt((raw['amount'] ?? raw['Amount']) ?? 0),
237
+ currencyCode: (raw['currencyCode'] ?? raw['CurrencyCode']),
238
+ merchantId: (raw['merchantId'] ?? raw['MerchantId']),
239
+ parentId: (raw['parentId'] ?? raw['ParentId']) ?? null,
240
+ insDate: (raw['insDate'] ?? raw['InsDate'] ?? ''),
241
+ transactionTypeId: (raw['transactionTypeId'] ?? raw['TransactionTypeId']) ?? 0,
242
+ ...(typeof cardNumber === 'string' ? { cardNumber } : {}),
243
+ ...(typeof cardTypeId === 'number' ? { cardTypeId } : {}),
244
+ ...(typeof email === 'string' ? { email } : {}),
245
+ ...(typeof fullName === 'string' ? { fullName } : {}),
246
+ ...(typeof merchantTrns === 'string' ? { merchantTrns } : {}),
247
+ ...(typeof customerTrns === 'string' ? { customerTrns } : {}),
248
+ ...(typeof connectedAccountId === 'string' ? { connectedAccountId } : {}),
249
+ };
250
+ }
251
+ /**
252
+ * Issue a full or partial refund for a captured transaction.
253
+ *
254
+ * IMPORTANT — probe-verified 2026-04-25 (F1):
255
+ * Viva returns 405 Method Not Allowed on `POST /checkout/v2/transactions/{id}`
256
+ * (the v2/OAuth2 path). The ONLY working refund path is:
257
+ * `POST /api/transactions/{transactionId}` on the LEGACY HOST
258
+ * (`demo.vivapayments.com` / `www.vivapayments.com`) with Basic auth
259
+ * (MerchantId:ApiKey) and form-urlencoded body.
260
+ *
261
+ * This method calls `legacyClient` DIRECTLY. The 401-fallback (D15) does NOT
262
+ * apply here — Viva returns 405 (not 401) on the v2 path, so no fallback
263
+ * could ever trigger.
264
+ *
265
+ * If `legacyClient` is not configured (absent from constructor), this method
266
+ * throws VivaValidationError with code VIVA_REFUND_REJECTED indicating that
267
+ * the basic-auth credentials are required and missing.
268
+ *
269
+ * Per plan P18:
270
+ * - Full refund: omit amountMinor (no Amount in form body per Viva convention).
271
+ * - Partial refund: provide amountMinor > 0 (Amount sent in form body).
272
+ * - ISV fee reverses automatically on refund (per isv-partner-program.txt:296).
273
+ * - Failed refund (4xx) surfaces as VivaApiError; payment NOT marked refunded.
274
+ *
275
+ * Non-idempotent: does not retry on 4xx/5xx.
276
+ *
277
+ * Viva response fields (PascalCase, mapped to camelCase):
278
+ * StatusId → statusId, Amount → amount, TransactionId → transactionId.
279
+ *
280
+ * @see references/viva-docs/md/tut-create-recurring-payment.txt:288 (legacy path + basic auth)
281
+ * @see references/viva-docs/md/isv-partner-program.txt:296 (ISV fee reversal on refund)
282
+ * @see references/viva-docs/md/merchant-id-and-api-key.txt:1 (basic auth credentials)
283
+ */
284
+ async refundPayment(transactionId, opts) {
285
+ // Local validation per P18
286
+ if (opts.amountMinor !== undefined && opts.amountMinor <= 0n) {
287
+ throw new VivaValidationError({
288
+ message: `refundPayment: amountMinor must be > 0 when specified, got ${opts.amountMinor}`,
289
+ });
290
+ }
291
+ // legacyClient REQUIRED for refund (F1 — probe-verified 2026-04-25).
292
+ if (!this.legacyClient) {
293
+ throw new VivaValidationError({
294
+ message: 'refundPayment requires a legacyClient (Basic auth with MerchantId + ApiKey). ' +
295
+ 'Configure VIVA_MERCHANT_ID and VIVA_API_KEY in plugin options. ' +
296
+ 'Viva returns 405 on the v2/OAuth2 refund path (probe-verified 2026-04-25).',
297
+ });
298
+ }
299
+ // Build form-urlencoded body.
300
+ // - Amount: send only for partial refund; omit for full refund per Viva convention.
301
+ // - SourceCode: defaults to 'Default'.
302
+ // @see references/viva-docs/md/tut-create-recurring-payment.txt:288
303
+ const formBody = {
304
+ SourceCode: opts.sourceCode ?? 'Default',
305
+ };
306
+ if (opts.amountMinor !== undefined) {
307
+ // Viva legacy endpoint expects amount in minor units as integer.
308
+ formBody['Amount'] = opts.amountMinor;
309
+ }
310
+ const result = await this.legacyClient.request({
311
+ method: 'POST',
312
+ path: `/api/transactions/${transactionId}`,
313
+ formBody,
314
+ idempotent: false, // non-idempotent POST — no 4xx/5xx retry
315
+ endpoint: 'POST /api/transactions/{transactionId}',
316
+ });
317
+ const raw = result.data;
318
+ // Map PascalCase → camelCase and return typed RefundResponse.
319
+ return {
320
+ transactionId: (raw.TransactionId ?? transactionId),
321
+ ...(raw.StatusId !== undefined ? { statusId: raw.StatusId } : {}),
322
+ ...(raw.Amount !== undefined ? { amount: BigInt(raw.Amount) } : {}),
323
+ };
324
+ }
325
+ /**
326
+ * Cancel an order that has not yet been paid.
327
+ *
328
+ * Idempotent per Viva docs: calling cancel on an already-cancelled or
329
+ * captured order returns the existing Viva response without error.
330
+ *
331
+ * Per plan P18: cancellation triggers webhook 4865 (Order Updated).
332
+ *
333
+ * Path: `DELETE /checkout/v2/orders/{orderCode}?merchantId={merchantId}` (OAuth2).
334
+ *
335
+ * UNVERIFIED against live sandbox as of 2026-04-25 probe. Only
336
+ * cancel-transaction (refund/reverse) was tested; cancel-order was not.
337
+ * Kept on v2/OAuth2 + 401-fallback path defensively.
338
+ *
339
+ * 401 → reseller fallback (D15) — kept DEFENSIVE:
340
+ * If the primary OAuth2 client receives a 401 and secondaryClient is configured,
341
+ * the request is retried once with the secondary (Reseller basic-auth) client.
342
+ * A 401 from the secondary surfaces immediately as VivaAuthError — no further retry.
343
+ *
344
+ * Note: if cancelOrder already succeeded on Viva's side before any 401 is
345
+ * observed, a 4xx from Viva on a subsequent attempt signals the order is
346
+ * already cancelled (idempotent). The fallback does NOT apply to non-401
347
+ * errors — those propagate as VivaApiError unchanged.
348
+ *
349
+ * @see references/viva-docs/md/payment-isv-api.txt:1
350
+ * @see references/viva-docs/md/webhooks-for-payments.txt:205 (4865 Order Updated)
351
+ * @see references/viva-docs/md/isv-credentials.txt:107 (reseller basic-auth)
352
+ * @see docs/plans/vendure-plugin-v0.md §D15 (reseller fallback scope)
353
+ */
354
+ async cancelOrder(orderCode, opts) {
355
+ const requestOpts = {
356
+ method: 'DELETE',
357
+ path: `/checkout/v2/orders/${orderCode}`,
358
+ query: { merchantId: opts.merchantId },
359
+ idempotent: true, // idempotent per Viva docs
360
+ endpoint: 'DELETE /checkout/v2/orders/{orderCode}',
361
+ };
362
+ let raw;
363
+ try {
364
+ raw = await this.client.request(requestOpts);
365
+ }
366
+ catch (err) {
367
+ // 401 → reseller fallback (D15). Only attempt if secondaryClient is present.
368
+ // A 401 from the secondary surfaces immediately — no further retry.
369
+ // @see docs/plans/vendure-plugin-v0.md §D15
370
+ // @see references/viva-docs/md/isv-credentials.txt:107
371
+ if (err instanceof VivaAuthError && err.httpStatus === 401 && this.secondaryClient) {
372
+ raw = await this.secondaryClient.request(requestOpts);
373
+ }
374
+ else {
375
+ throw err;
376
+ }
377
+ }
378
+ return {
379
+ orderCode: raw.OrderCode,
380
+ errorCode: raw.ErrorCode,
381
+ errorText: raw.ErrorText,
382
+ };
383
+ }
384
+ }
385
+ //# sourceMappingURL=payments.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"payments.js","sourceRoot":"","sources":["../../src/isv/payments.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * IsvSources — ISV-mode admin operations on payment sources for connected merchants.
3
+ *
4
+ * Wraps `POST /api/sources` on the Viva legacy host using a `BasicAuthClient`
5
+ * configured with `authVariant: 'reseller'`. A "source" is a payment-source
6
+ * configuration on a merchant account — e.g. a Smart Checkout source linked to
7
+ * a domain + success/fail callback paths, or a physical (in-store) source.
8
+ *
9
+ * The reseller credentials baked into the underlying `BasicAuthClient` are
10
+ * scoped to **one** connected merchant per client instance. To operate on
11
+ * multiple merchants under the same reseller account, construct multiple
12
+ * `BasicAuthClient` instances (one per merchant) and pass each to its own
13
+ * `IsvSources`.
14
+ *
15
+ * @see references/payment-isv-api.yaml:135
16
+ * @see docs/AUTH.md §1.2 (Reseller Basic)
17
+ * @see docs/ENDPOINTS.md §5.1
18
+ */
19
+ import type { BasicAuthClient } from '../legacy/client.js';
20
+ /**
21
+ * Input for `createEcommerceSource` — Smart Checkout source for a website.
22
+ */
23
+ export interface CreateEcommerceSourceInput {
24
+ /** Domain the source is bound to, e.g. `www.example.com`. */
25
+ domain: string;
26
+ /** URL path the customer is redirected to after a successful checkout. */
27
+ pathSuccess: string;
28
+ /** URL path the customer is redirected to after a failed checkout. */
29
+ pathFail: string;
30
+ /** Friendly label for the source (optional). */
31
+ name?: string;
32
+ /**
33
+ * 4-digit source code (1000..9999). Auto-assigned by Viva when omitted.
34
+ */
35
+ sourceCode?: number;
36
+ /** Whether the domain is served over HTTPS. Defaults to `true`. */
37
+ isSecure?: boolean;
38
+ }
39
+ /**
40
+ * Input for `createPhysicalSource` — in-store / terminal source.
41
+ */
42
+ export interface CreatePhysicalSourceInput {
43
+ /** Friendly label for the physical source. Required. */
44
+ name: string;
45
+ /** 4-digit source code (1000..9999). Auto-assigned by Viva when omitted. */
46
+ sourceCode?: number;
47
+ }
48
+ /**
49
+ * Response shape from `POST /api/sources`. Kept permissive — Viva's response
50
+ * may include additional fields depending on the source type / account state.
51
+ */
52
+ export interface SourceResponse {
53
+ sourceCode: number;
54
+ name?: string;
55
+ [k: string]: unknown;
56
+ }
57
+ export declare class IsvSources {
58
+ private readonly basic;
59
+ /**
60
+ * @param basic A `BasicAuthClient` already configured with
61
+ * `authVariant: 'reseller'`. The reseller credentials are tied to ONE
62
+ * connected merchant per client instance.
63
+ */
64
+ constructor(basic: BasicAuthClient);
65
+ /**
66
+ * Create a Smart Checkout (ecommerce) payment source for the connected
67
+ * merchant.
68
+ *
69
+ * @see docs/ENDPOINTS.md §5.1
70
+ */
71
+ createEcommerceSource(input: CreateEcommerceSourceInput): Promise<SourceResponse>;
72
+ /**
73
+ * Create a physical (in-store / terminal) payment source for the connected
74
+ * merchant.
75
+ *
76
+ * @see docs/ENDPOINTS.md §5.1
77
+ */
78
+ createPhysicalSource(input: CreatePhysicalSourceInput): Promise<SourceResponse>;
79
+ }
80
+ //# sourceMappingURL=sources.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sources.d.ts","sourceRoot":"","sources":["../../src/isv/sources.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAO3D;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC,6DAA6D;IAC7D,MAAM,EAAE,MAAM,CAAC;IACf,0EAA0E;IAC1E,WAAW,EAAE,MAAM,CAAC;IACpB,sEAAsE;IACtE,QAAQ,EAAE,MAAM,CAAC;IACjB,gDAAgD;IAChD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mEAAmE;IACnE,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,wDAAwD;IACxD,IAAI,EAAE,MAAM,CAAC;IACb,4EAA4E;IAC5E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AA8BD,qBAAa,UAAU;IAMT,OAAO,CAAC,QAAQ,CAAC,KAAK;IALlC;;;;OAIG;gBAC0B,KAAK,EAAE,eAAe;IAEnD;;;;;OAKG;IACG,qBAAqB,CAAC,KAAK,EAAE,0BAA0B,GAAG,OAAO,CAAC,cAAc,CAAC;IA6BvF;;;;;OAKG;IACG,oBAAoB,CAAC,KAAK,EAAE,yBAAyB,GAAG,OAAO,CAAC,cAAc,CAAC;CAqBtF"}
@@ -0,0 +1,112 @@
1
+ /**
2
+ * IsvSources — ISV-mode admin operations on payment sources for connected merchants.
3
+ *
4
+ * Wraps `POST /api/sources` on the Viva legacy host using a `BasicAuthClient`
5
+ * configured with `authVariant: 'reseller'`. A "source" is a payment-source
6
+ * configuration on a merchant account — e.g. a Smart Checkout source linked to
7
+ * a domain + success/fail callback paths, or a physical (in-store) source.
8
+ *
9
+ * The reseller credentials baked into the underlying `BasicAuthClient` are
10
+ * scoped to **one** connected merchant per client instance. To operate on
11
+ * multiple merchants under the same reseller account, construct multiple
12
+ * `BasicAuthClient` instances (one per merchant) and pass each to its own
13
+ * `IsvSources`.
14
+ *
15
+ * @see references/payment-isv-api.yaml:135
16
+ * @see docs/AUTH.md §1.2 (Reseller Basic)
17
+ * @see docs/ENDPOINTS.md §5.1
18
+ */
19
+ import { VivaValidationError } from '../errors/index.js';
20
+ // ---------------------------------------------------------------------------
21
+ // Validation helpers
22
+ // ---------------------------------------------------------------------------
23
+ const SOURCE_CODE_MIN = 1000;
24
+ const SOURCE_CODE_MAX = 9999;
25
+ function requireNonEmptyString(value, field) {
26
+ if (typeof value !== 'string' || value.trim() === '') {
27
+ throw new VivaValidationError({
28
+ message: `IsvSources: ${field} is required and must be a non-empty string`,
29
+ });
30
+ }
31
+ }
32
+ function validateSourceCode(value) {
33
+ if (value === undefined)
34
+ return;
35
+ if (!Number.isInteger(value) || value < SOURCE_CODE_MIN || value > SOURCE_CODE_MAX) {
36
+ throw new VivaValidationError({
37
+ message: `IsvSources: sourceCode must be a 4-digit integer in [${SOURCE_CODE_MIN}, ${SOURCE_CODE_MAX}]`,
38
+ });
39
+ }
40
+ }
41
+ // ---------------------------------------------------------------------------
42
+ // IsvSources
43
+ // ---------------------------------------------------------------------------
44
+ export class IsvSources {
45
+ basic;
46
+ /**
47
+ * @param basic A `BasicAuthClient` already configured with
48
+ * `authVariant: 'reseller'`. The reseller credentials are tied to ONE
49
+ * connected merchant per client instance.
50
+ */
51
+ constructor(basic) {
52
+ this.basic = basic;
53
+ }
54
+ /**
55
+ * Create a Smart Checkout (ecommerce) payment source for the connected
56
+ * merchant.
57
+ *
58
+ * @see docs/ENDPOINTS.md §5.1
59
+ */
60
+ async createEcommerceSource(input) {
61
+ requireNonEmptyString(input.domain, 'domain');
62
+ requireNonEmptyString(input.pathSuccess, 'pathSuccess');
63
+ requireNonEmptyString(input.pathFail, 'pathFail');
64
+ validateSourceCode(input.sourceCode);
65
+ const body = {
66
+ domain: input.domain,
67
+ isSecure: input.isSecure ?? true,
68
+ pathFail: input.pathFail,
69
+ pathSuccess: input.pathSuccess,
70
+ };
71
+ if (input.name !== undefined) {
72
+ body['name'] = input.name;
73
+ }
74
+ if (input.sourceCode !== undefined) {
75
+ body['sourceCode'] = input.sourceCode;
76
+ }
77
+ const result = await this.basic.request({
78
+ method: 'POST',
79
+ path: '/api/sources',
80
+ jsonBody: body,
81
+ idempotent: false,
82
+ endpoint: 'POST /api/sources',
83
+ });
84
+ return result.data;
85
+ }
86
+ /**
87
+ * Create a physical (in-store / terminal) payment source for the connected
88
+ * merchant.
89
+ *
90
+ * @see docs/ENDPOINTS.md §5.1
91
+ */
92
+ async createPhysicalSource(input) {
93
+ requireNonEmptyString(input.name, 'name');
94
+ validateSourceCode(input.sourceCode);
95
+ const body = {
96
+ isPhysical: true,
97
+ name: input.name,
98
+ };
99
+ if (input.sourceCode !== undefined) {
100
+ body['sourceCode'] = input.sourceCode;
101
+ }
102
+ const result = await this.basic.request({
103
+ method: 'POST',
104
+ path: '/api/sources',
105
+ jsonBody: body,
106
+ idempotent: false,
107
+ endpoint: 'POST /api/sources',
108
+ });
109
+ return result.data;
110
+ }
111
+ }
112
+ //# sourceMappingURL=sources.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sources.js","sourceRoot":"","sources":["../../src/isv/sources.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * IsvWebhooks — ISV Webhook Registration API.
3
+ *
4
+ * Probe-verified 2026-05-11. Endpoints below match `docs/payment-isv-api.yaml`.
5
+ *
6
+ * - registerWebhook → POST /isv/v1/webhooks (204 No Content)
7
+ * - getVerificationKey → GET /isv/v1/webhooks/token (200 {key})
8
+ *
9
+ * Intentionally absent — these endpoints are NOT exposed by the ISV API:
10
+ *
11
+ * - listWebhooks (no GET on /isv/v1/webhooks; only POST)
12
+ * - deactivate/delete (no PATCH/DELETE; manage existing entries via the
13
+ * banking UI or by re-registering)
14
+ *
15
+ * Auth: OAuth2 Bearer with scopes
16
+ * `urn:viva:payments:core:api:isv urn:viva:payments:core:api:redirectcheckout`.
17
+ *
18
+ * Limits: max 10 URLs per `eventTypeId`. Exceeding the cap returns HTTP 400
19
+ * with `eventId: 3732` (`SecurityCreateWebhookFailedLimitReached`).
20
+ */
21
+ import type { IsvHttpClient } from './client.js';
22
+ import type { RegisterWebhookRequest, RetrieveWebhookKeyResponse } from '../types/index.js';
23
+ export declare class IsvWebhooks {
24
+ private readonly client;
25
+ constructor(client: IsvHttpClient);
26
+ /**
27
+ * Register a webhook URL for an event type.
28
+ *
29
+ * Server returns 204 No Content on success. Re-posting the same URL for
30
+ * the same event type does not error — it is the caller's responsibility
31
+ * to avoid duplicates (the API has no list endpoint).
32
+ *
33
+ * Throws `VivaApiError` with `vivaCode: '3732'` if the 10-URL-per-event cap
34
+ * is exceeded.
35
+ */
36
+ registerWebhook(req: RegisterWebhookRequest): Promise<void>;
37
+ /**
38
+ * Retrieve the ISV-level webhook verification key.
39
+ *
40
+ * The returned `key` must be echoed in the JSON response to the URL-verify
41
+ * GET handshake Viva performs against the webhook endpoint.
42
+ *
43
+ * Note: a single key is issued per ISV account; it does not vary per
44
+ * registered URL.
45
+ */
46
+ getVerificationKey(): Promise<RetrieveWebhookKeyResponse>;
47
+ }
48
+ //# sourceMappingURL=webhooks-api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhooks-api.d.ts","sourceRoot":"","sources":["../../src/isv/webhooks-api.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EACV,sBAAsB,EACtB,0BAA0B,EAC3B,MAAM,mBAAmB,CAAC;AAE3B,qBAAa,WAAW;IACV,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,aAAa;IAElD;;;;;;;;;OASG;IACG,eAAe,CAAC,GAAG,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAajE;;;;;;;;OAQG;IACG,kBAAkB,IAAI,OAAO,CAAC,0BAA0B,CAAC;CAQhE"}