@enfuce/nextgen-sdk 0.0.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 (313) hide show
  1. package/dist/authorisation-control/api.d.ts +771 -0
  2. package/dist/authorisation-control/api.js +240 -0
  3. package/dist/authorisation-control/base.d.ts +66 -0
  4. package/dist/authorisation-control/base.js +65 -0
  5. package/dist/authorisation-control/common.d.ts +65 -0
  6. package/dist/authorisation-control/common.js +161 -0
  7. package/dist/authorisation-control/configuration.d.ts +91 -0
  8. package/dist/authorisation-control/configuration.js +44 -0
  9. package/dist/authorisation-control/index.d.ts +13 -0
  10. package/dist/authorisation-control/index.js +31 -0
  11. package/dist/card/api.d.ts +2065 -0
  12. package/dist/card/api.js +1406 -0
  13. package/dist/card/base.d.ts +66 -0
  14. package/dist/card/base.js +65 -0
  15. package/dist/card/common.d.ts +65 -0
  16. package/dist/card/common.js +161 -0
  17. package/dist/card/configuration.d.ts +91 -0
  18. package/dist/card/configuration.js +44 -0
  19. package/dist/card/index.d.ts +13 -0
  20. package/dist/card/index.js +31 -0
  21. package/dist/cardholder/api.d.ts +1890 -0
  22. package/dist/cardholder/api.js +1239 -0
  23. package/dist/cardholder/base.d.ts +66 -0
  24. package/dist/cardholder/base.js +65 -0
  25. package/dist/cardholder/common.d.ts +65 -0
  26. package/dist/cardholder/common.js +161 -0
  27. package/dist/cardholder/configuration.d.ts +91 -0
  28. package/dist/cardholder/configuration.js +44 -0
  29. package/dist/cardholder/index.d.ts +13 -0
  30. package/dist/cardholder/index.js +31 -0
  31. package/dist/cards/api.d.ts +78 -0
  32. package/dist/cards/api.js +142 -0
  33. package/dist/cards/base.d.ts +66 -0
  34. package/dist/cards/base.js +65 -0
  35. package/dist/cards/common.d.ts +65 -0
  36. package/dist/cards/common.js +161 -0
  37. package/dist/cards/configuration.d.ts +91 -0
  38. package/dist/cards/configuration.js +44 -0
  39. package/dist/cards/index.d.ts +13 -0
  40. package/dist/cards/index.js +31 -0
  41. package/dist/clearing-file-copy/api.d.ts +1245 -0
  42. package/dist/clearing-file-copy/api.js +139 -0
  43. package/dist/clearing-file-copy/base.d.ts +66 -0
  44. package/dist/clearing-file-copy/base.js +65 -0
  45. package/dist/clearing-file-copy/common.d.ts +65 -0
  46. package/dist/clearing-file-copy/common.js +161 -0
  47. package/dist/clearing-file-copy/configuration.d.ts +91 -0
  48. package/dist/clearing-file-copy/configuration.js +44 -0
  49. package/dist/clearing-file-copy/index.d.ts +13 -0
  50. package/dist/clearing-file-copy/index.js +31 -0
  51. package/dist/esm/authorisation-control/api.d.ts +771 -0
  52. package/dist/esm/authorisation-control/api.js +233 -0
  53. package/dist/esm/authorisation-control/base.d.ts +66 -0
  54. package/dist/esm/authorisation-control/base.js +60 -0
  55. package/dist/esm/authorisation-control/common.d.ts +65 -0
  56. package/dist/esm/authorisation-control/common.js +149 -0
  57. package/dist/esm/authorisation-control/configuration.d.ts +91 -0
  58. package/dist/esm/authorisation-control/configuration.js +40 -0
  59. package/dist/esm/authorisation-control/index.d.ts +13 -0
  60. package/dist/esm/authorisation-control/index.js +15 -0
  61. package/dist/esm/card/api.d.ts +2065 -0
  62. package/dist/esm/card/api.js +1379 -0
  63. package/dist/esm/card/base.d.ts +66 -0
  64. package/dist/esm/card/base.js +60 -0
  65. package/dist/esm/card/common.d.ts +65 -0
  66. package/dist/esm/card/common.js +149 -0
  67. package/dist/esm/card/configuration.d.ts +91 -0
  68. package/dist/esm/card/configuration.js +40 -0
  69. package/dist/esm/card/index.d.ts +13 -0
  70. package/dist/esm/card/index.js +15 -0
  71. package/dist/esm/cardholder/api.d.ts +1890 -0
  72. package/dist/esm/cardholder/api.js +1220 -0
  73. package/dist/esm/cardholder/base.d.ts +66 -0
  74. package/dist/esm/cardholder/base.js +60 -0
  75. package/dist/esm/cardholder/common.d.ts +65 -0
  76. package/dist/esm/cardholder/common.js +149 -0
  77. package/dist/esm/cardholder/configuration.d.ts +91 -0
  78. package/dist/esm/cardholder/configuration.js +40 -0
  79. package/dist/esm/cardholder/index.d.ts +13 -0
  80. package/dist/esm/cardholder/index.js +15 -0
  81. package/dist/esm/cards/api.d.ts +78 -0
  82. package/dist/esm/cards/api.js +135 -0
  83. package/dist/esm/cards/base.d.ts +66 -0
  84. package/dist/esm/cards/base.js +60 -0
  85. package/dist/esm/cards/common.d.ts +65 -0
  86. package/dist/esm/cards/common.js +149 -0
  87. package/dist/esm/cards/configuration.d.ts +91 -0
  88. package/dist/esm/cards/configuration.js +40 -0
  89. package/dist/esm/cards/index.d.ts +13 -0
  90. package/dist/esm/cards/index.js +15 -0
  91. package/dist/esm/clearing-file-copy/api.d.ts +1245 -0
  92. package/dist/esm/clearing-file-copy/api.js +136 -0
  93. package/dist/esm/clearing-file-copy/base.d.ts +66 -0
  94. package/dist/esm/clearing-file-copy/base.js +60 -0
  95. package/dist/esm/clearing-file-copy/common.d.ts +65 -0
  96. package/dist/esm/clearing-file-copy/common.js +149 -0
  97. package/dist/esm/clearing-file-copy/configuration.d.ts +91 -0
  98. package/dist/esm/clearing-file-copy/configuration.js +40 -0
  99. package/dist/esm/clearing-file-copy/index.d.ts +13 -0
  100. package/dist/esm/clearing-file-copy/index.js +15 -0
  101. package/dist/esm/index.d.ts +12 -0
  102. package/dist/esm/index.js +14 -0
  103. package/dist/esm/issuer-events/api.d.ts +1721 -0
  104. package/dist/esm/issuer-events/api.js +940 -0
  105. package/dist/esm/issuer-events/base.d.ts +66 -0
  106. package/dist/esm/issuer-events/base.js +60 -0
  107. package/dist/esm/issuer-events/common.d.ts +65 -0
  108. package/dist/esm/issuer-events/common.js +149 -0
  109. package/dist/esm/issuer-events/configuration.d.ts +91 -0
  110. package/dist/esm/issuer-events/configuration.js +40 -0
  111. package/dist/esm/issuer-events/index.d.ts +13 -0
  112. package/dist/esm/issuer-events/index.js +15 -0
  113. package/dist/esm/oauth/axios.d.ts +14 -0
  114. package/dist/esm/oauth/axios.js +58 -0
  115. package/dist/esm/oauth/clientCredentials.d.ts +24 -0
  116. package/dist/esm/oauth/clientCredentials.js +59 -0
  117. package/dist/esm/oauth/index.d.ts +3 -0
  118. package/dist/esm/oauth/index.js +24 -0
  119. package/dist/esm/oauth/tokenManager.d.ts +38 -0
  120. package/dist/esm/oauth/tokenManager.js +77 -0
  121. package/dist/esm/pin/api.d.ts +329 -0
  122. package/dist/esm/pin/api.js +341 -0
  123. package/dist/esm/pin/base.d.ts +66 -0
  124. package/dist/esm/pin/base.js +60 -0
  125. package/dist/esm/pin/common.d.ts +65 -0
  126. package/dist/esm/pin/common.js +149 -0
  127. package/dist/esm/pin/configuration.d.ts +91 -0
  128. package/dist/esm/pin/configuration.js +40 -0
  129. package/dist/esm/pin/index.d.ts +13 -0
  130. package/dist/esm/pin/index.js +15 -0
  131. package/dist/esm/threeds/api.d.ts +104 -0
  132. package/dist/esm/threeds/api.js +136 -0
  133. package/dist/esm/threeds/base.d.ts +66 -0
  134. package/dist/esm/threeds/base.js +60 -0
  135. package/dist/esm/threeds/common.d.ts +65 -0
  136. package/dist/esm/threeds/common.js +149 -0
  137. package/dist/esm/threeds/configuration.d.ts +91 -0
  138. package/dist/esm/threeds/configuration.js +40 -0
  139. package/dist/esm/threeds/index.d.ts +13 -0
  140. package/dist/esm/threeds/index.js +15 -0
  141. package/dist/esm/threeds-oob/api.d.ts +241 -0
  142. package/dist/esm/threeds-oob/api.js +141 -0
  143. package/dist/esm/threeds-oob/base.d.ts +66 -0
  144. package/dist/esm/threeds-oob/base.js +60 -0
  145. package/dist/esm/threeds-oob/common.d.ts +65 -0
  146. package/dist/esm/threeds-oob/common.js +149 -0
  147. package/dist/esm/threeds-oob/configuration.d.ts +91 -0
  148. package/dist/esm/threeds-oob/configuration.js +40 -0
  149. package/dist/esm/threeds-oob/index.d.ts +13 -0
  150. package/dist/esm/threeds-oob/index.js +15 -0
  151. package/dist/esm/transaction-event/api.d.ts +1082 -0
  152. package/dist/esm/transaction-event/api.js +163 -0
  153. package/dist/esm/transaction-event/base.d.ts +66 -0
  154. package/dist/esm/transaction-event/base.js +60 -0
  155. package/dist/esm/transaction-event/common.d.ts +65 -0
  156. package/dist/esm/transaction-event/common.js +149 -0
  157. package/dist/esm/transaction-event/configuration.d.ts +91 -0
  158. package/dist/esm/transaction-event/configuration.js +40 -0
  159. package/dist/esm/transaction-event/index.d.ts +13 -0
  160. package/dist/esm/transaction-event/index.js +15 -0
  161. package/dist/esm/wallet/api.d.ts +1385 -0
  162. package/dist/esm/wallet/api.js +1342 -0
  163. package/dist/esm/wallet/base.d.ts +66 -0
  164. package/dist/esm/wallet/base.js +60 -0
  165. package/dist/esm/wallet/common.d.ts +65 -0
  166. package/dist/esm/wallet/common.js +149 -0
  167. package/dist/esm/wallet/configuration.d.ts +91 -0
  168. package/dist/esm/wallet/configuration.js +40 -0
  169. package/dist/esm/wallet/index.d.ts +13 -0
  170. package/dist/esm/wallet/index.js +15 -0
  171. package/dist/index.d.ts +12 -0
  172. package/dist/index.js +17 -0
  173. package/dist/issuer-events/api.d.ts +1721 -0
  174. package/dist/issuer-events/api.js +947 -0
  175. package/dist/issuer-events/base.d.ts +66 -0
  176. package/dist/issuer-events/base.js +65 -0
  177. package/dist/issuer-events/common.d.ts +65 -0
  178. package/dist/issuer-events/common.js +161 -0
  179. package/dist/issuer-events/configuration.d.ts +91 -0
  180. package/dist/issuer-events/configuration.js +44 -0
  181. package/dist/issuer-events/index.d.ts +13 -0
  182. package/dist/issuer-events/index.js +31 -0
  183. package/dist/oauth/axios.d.ts +14 -0
  184. package/dist/oauth/axios.js +61 -0
  185. package/dist/oauth/clientCredentials.d.ts +24 -0
  186. package/dist/oauth/clientCredentials.js +63 -0
  187. package/dist/oauth/index.d.ts +3 -0
  188. package/dist/oauth/index.js +31 -0
  189. package/dist/oauth/tokenManager.d.ts +38 -0
  190. package/dist/oauth/tokenManager.js +81 -0
  191. package/dist/pin/api.d.ts +329 -0
  192. package/dist/pin/api.js +352 -0
  193. package/dist/pin/base.d.ts +66 -0
  194. package/dist/pin/base.js +65 -0
  195. package/dist/pin/common.d.ts +65 -0
  196. package/dist/pin/common.js +161 -0
  197. package/dist/pin/configuration.d.ts +91 -0
  198. package/dist/pin/configuration.js +44 -0
  199. package/dist/pin/index.d.ts +13 -0
  200. package/dist/pin/index.js +31 -0
  201. package/dist/threeds/api.d.ts +104 -0
  202. package/dist/threeds/api.js +143 -0
  203. package/dist/threeds/base.d.ts +66 -0
  204. package/dist/threeds/base.js +65 -0
  205. package/dist/threeds/common.d.ts +65 -0
  206. package/dist/threeds/common.js +161 -0
  207. package/dist/threeds/configuration.d.ts +91 -0
  208. package/dist/threeds/configuration.js +44 -0
  209. package/dist/threeds/index.d.ts +13 -0
  210. package/dist/threeds/index.js +31 -0
  211. package/dist/threeds-oob/api.d.ts +241 -0
  212. package/dist/threeds-oob/api.js +148 -0
  213. package/dist/threeds-oob/base.d.ts +66 -0
  214. package/dist/threeds-oob/base.js +65 -0
  215. package/dist/threeds-oob/common.d.ts +65 -0
  216. package/dist/threeds-oob/common.js +161 -0
  217. package/dist/threeds-oob/configuration.d.ts +91 -0
  218. package/dist/threeds-oob/configuration.js +44 -0
  219. package/dist/threeds-oob/index.d.ts +13 -0
  220. package/dist/threeds-oob/index.js +31 -0
  221. package/dist/transaction-event/api.d.ts +1082 -0
  222. package/dist/transaction-event/api.js +166 -0
  223. package/dist/transaction-event/base.d.ts +66 -0
  224. package/dist/transaction-event/base.js +65 -0
  225. package/dist/transaction-event/common.d.ts +65 -0
  226. package/dist/transaction-event/common.js +161 -0
  227. package/dist/transaction-event/configuration.d.ts +91 -0
  228. package/dist/transaction-event/configuration.js +44 -0
  229. package/dist/transaction-event/index.d.ts +13 -0
  230. package/dist/transaction-event/index.js +31 -0
  231. package/dist/wallet/api.d.ts +1385 -0
  232. package/dist/wallet/api.js +1377 -0
  233. package/dist/wallet/base.d.ts +66 -0
  234. package/dist/wallet/base.js +65 -0
  235. package/dist/wallet/common.d.ts +65 -0
  236. package/dist/wallet/common.js +161 -0
  237. package/dist/wallet/configuration.d.ts +91 -0
  238. package/dist/wallet/configuration.js +44 -0
  239. package/dist/wallet/index.d.ts +13 -0
  240. package/dist/wallet/index.js +31 -0
  241. package/package.json +25 -0
  242. package/src/authorisation-control/api.ts +876 -0
  243. package/src/authorisation-control/base.ts +86 -0
  244. package/src/authorisation-control/common.ts +150 -0
  245. package/src/authorisation-control/configuration.ts +115 -0
  246. package/src/authorisation-control/index.ts +18 -0
  247. package/src/card/api.ts +2792 -0
  248. package/src/card/base.ts +86 -0
  249. package/src/card/common.ts +150 -0
  250. package/src/card/configuration.ts +115 -0
  251. package/src/card/index.ts +18 -0
  252. package/src/cardholder/api.ts +2244 -0
  253. package/src/cardholder/base.ts +86 -0
  254. package/src/cardholder/common.ts +150 -0
  255. package/src/cardholder/configuration.ts +115 -0
  256. package/src/cardholder/index.ts +18 -0
  257. package/src/cards/api.ts +141 -0
  258. package/src/cards/base.ts +86 -0
  259. package/src/cards/common.ts +150 -0
  260. package/src/cards/configuration.ts +115 -0
  261. package/src/cards/index.ts +18 -0
  262. package/src/clearing-file-copy/api.ts +1309 -0
  263. package/src/clearing-file-copy/base.ts +86 -0
  264. package/src/clearing-file-copy/common.ts +150 -0
  265. package/src/clearing-file-copy/configuration.ts +115 -0
  266. package/src/clearing-file-copy/index.ts +18 -0
  267. package/src/index.ts +16 -0
  268. package/src/issuer-events/api.ts +1926 -0
  269. package/src/issuer-events/base.ts +86 -0
  270. package/src/issuer-events/common.ts +150 -0
  271. package/src/issuer-events/configuration.ts +115 -0
  272. package/src/issuer-events/index.ts +18 -0
  273. package/src/oauth/axios.ts +60 -0
  274. package/src/oauth/clientCredentials.ts +72 -0
  275. package/src/oauth/index.ts +24 -0
  276. package/src/oauth/tokenManager.ts +85 -0
  277. package/src/pin/api.ts +507 -0
  278. package/src/pin/base.ts +86 -0
  279. package/src/pin/common.ts +150 -0
  280. package/src/pin/configuration.ts +115 -0
  281. package/src/pin/index.ts +18 -0
  282. package/src/threeds/api.ts +173 -0
  283. package/src/threeds/base.ts +86 -0
  284. package/src/threeds/common.ts +150 -0
  285. package/src/threeds/configuration.ts +115 -0
  286. package/src/threeds/index.ts +18 -0
  287. package/src/threeds-oob/api.ts +311 -0
  288. package/src/threeds-oob/base.ts +86 -0
  289. package/src/threeds-oob/common.ts +150 -0
  290. package/src/threeds-oob/configuration.ts +115 -0
  291. package/src/threeds-oob/index.ts +18 -0
  292. package/src/transaction-event/api.ts +1152 -0
  293. package/src/transaction-event/base.ts +86 -0
  294. package/src/transaction-event/common.ts +150 -0
  295. package/src/transaction-event/configuration.ts +115 -0
  296. package/src/transaction-event/index.ts +18 -0
  297. package/src/wallet/api.ts +2083 -0
  298. package/src/wallet/base.ts +86 -0
  299. package/src/wallet/common.ts +150 -0
  300. package/src/wallet/configuration.ts +115 -0
  301. package/src/wallet/index.ts +18 -0
  302. package/test/authorisation-control.test.ts +71 -0
  303. package/test/card.test.ts +39 -0
  304. package/test/cardholder.test.ts +51 -0
  305. package/test/cards.test.ts +35 -0
  306. package/test/issuer-events.test.ts +55 -0
  307. package/test/oauth.test.ts +205 -0
  308. package/test/pin.test.ts +39 -0
  309. package/test/threeds-oob.test.ts +90 -0
  310. package/test/threeds.test.ts +55 -0
  311. package/test/wallet.test.ts +62 -0
  312. package/tsconfig.esm.json +7 -0
  313. package/tsconfig.json +14 -0
@@ -0,0 +1,205 @@
1
+ /**
2
+ * Tests for the hand-written OAuth token-management helper (src/oauth).
3
+ *
4
+ * Covers the TokenManager cache/refresh/single-flight logic, the client-credentials
5
+ * fetcher and the reactive 401-retry axios instance, using capturing axios adapters
6
+ * so nothing hits the network.
7
+ */
8
+ import axios, { type AxiosAdapter, type InternalAxiosRequestConfig } from 'axios';
9
+ import { describe, expect, it } from 'vitest';
10
+ import { oauth } from '../src';
11
+
12
+ const { TokenManager, clientCredentialsFetcher, clientCredentials, createOAuthAxios } = oauth;
13
+
14
+ function makeClock(start = 1000) {
15
+ const state = { t: start };
16
+ return { now: () => state.t, advance: (ms: number) => (state.t += ms), state };
17
+ }
18
+
19
+ function countingFetcher(expiresInSeconds = 300) {
20
+ const calls = { n: 0 };
21
+ const fetch = async () => {
22
+ calls.n += 1;
23
+ return { accessToken: `token-${calls.n}`, expiresInSeconds };
24
+ };
25
+ return { fetch, calls };
26
+ }
27
+
28
+ describe('TokenManager', () => {
29
+ it('caches the token within its validity window', async () => {
30
+ const { fetch, calls } = countingFetcher();
31
+ const clock = makeClock();
32
+ const mgr = new TokenManager(fetch, 60, clock.now);
33
+
34
+ expect(await mgr.getToken()).toBe('token-1');
35
+ expect(await mgr.getToken()).toBe('token-1');
36
+ expect(calls.n).toBe(1);
37
+ });
38
+
39
+ it('refreshes once past expiry minus skew', async () => {
40
+ const { fetch, calls } = countingFetcher(300);
41
+ const clock = makeClock();
42
+ const mgr = new TokenManager(fetch, 60, clock.now);
43
+
44
+ expect(await mgr.getToken()).toBe('token-1');
45
+ clock.advance(239_000);
46
+ expect(await mgr.getToken()).toBe('token-1');
47
+ expect(calls.n).toBe(1);
48
+
49
+ clock.advance(2_000); // 241s elapsed > 300 - 60
50
+ expect(await mgr.getToken()).toBe('token-2');
51
+ expect(calls.n).toBe(2);
52
+ });
53
+
54
+ it('refetches every call when lifetime is unknown', async () => {
55
+ const { fetch, calls } = countingFetcher(0);
56
+ const mgr = new TokenManager(fetch, 60, makeClock().now);
57
+ await mgr.getToken();
58
+ await mgr.getToken();
59
+ expect(calls.n).toBe(2);
60
+ });
61
+
62
+ it('shares a single in-flight fetch across concurrent callers', async () => {
63
+ const { fetch, calls } = countingFetcher();
64
+ const mgr = new TokenManager(fetch, 60, makeClock().now);
65
+
66
+ const results = await Promise.all([mgr.getToken(), mgr.getToken(), mgr.getToken()]);
67
+
68
+ expect(calls.n).toBe(1);
69
+ expect(results).toEqual(['token-1', 'token-1', 'token-1']);
70
+ });
71
+
72
+ it('forceRefresh is a no-op when the cached token already moved on', async () => {
73
+ const { fetch, calls } = countingFetcher();
74
+ const mgr = new TokenManager(fetch, 60, makeClock().now);
75
+
76
+ expect(await mgr.getToken()).toBe('token-1');
77
+ expect(await mgr.forceRefresh('an-older-token')).toBe('token-1');
78
+ expect(calls.n).toBe(1);
79
+
80
+ expect(await mgr.forceRefresh('token-1')).toBe('token-2');
81
+ expect(calls.n).toBe(2);
82
+ });
83
+ });
84
+
85
+ describe('clientCredentialsFetcher', () => {
86
+ function capturingAxios(response: unknown) {
87
+ const captured: { config?: InternalAxiosRequestConfig } = {};
88
+ const adapter: AxiosAdapter = async (config) => {
89
+ captured.config = config;
90
+ return { data: response, status: 200, statusText: 'OK', headers: {}, config };
91
+ };
92
+ return { captured, instance: axios.create({ adapter }) };
93
+ }
94
+
95
+ it('POSTs a form body with Basic auth and parses the token', async () => {
96
+ const { captured, instance } = capturingAxios({ access_token: 'abc', expires_in: 120 });
97
+ const fetch = clientCredentialsFetcher({
98
+ tokenUrl: 'https://auth.example.com/oauth/token',
99
+ clientId: 'my-id',
100
+ clientSecret: 'my-secret',
101
+ scopes: ['cards:read', 'cards:write'],
102
+ axiosInstance: instance,
103
+ });
104
+
105
+ const token = await fetch();
106
+
107
+ expect(token).toEqual({ accessToken: 'abc', expiresInSeconds: 120 });
108
+ expect(captured.config?.url).toBe('https://auth.example.com/oauth/token');
109
+ expect(captured.config?.method).toBe('post');
110
+ expect(captured.config?.data).toContain('grant_type=client_credentials');
111
+ expect(captured.config?.data).toContain('scope=cards%3Aread+cards%3Awrite');
112
+ expect(captured.config?.auth).toEqual({ username: 'my-id', password: 'my-secret' });
113
+ });
114
+
115
+ it('sends credentials in the body when authStyle is "body"', async () => {
116
+ const { captured, instance } = capturingAxios({ access_token: 'abc', expires_in: 60 });
117
+ const fetch = clientCredentialsFetcher({
118
+ tokenUrl: 'https://auth.example.com/oauth/token',
119
+ clientId: 'my-id',
120
+ clientSecret: 'my-secret',
121
+ authStyle: 'body',
122
+ axiosInstance: instance,
123
+ });
124
+
125
+ await fetch();
126
+
127
+ expect(captured.config?.data).toContain('client_id=my-id');
128
+ expect(captured.config?.data).toContain('client_secret=my-secret');
129
+ expect(captured.config?.auth).toBeUndefined();
130
+ });
131
+
132
+ it('clientCredentials returns a caching TokenManager', async () => {
133
+ const { instance } = capturingAxios({ access_token: 'abc', expires_in: 120 });
134
+ const mgr = clientCredentials(
135
+ { tokenUrl: 'https://auth.example.com/oauth/token', clientId: 'id', clientSecret: 's', axiosInstance: instance },
136
+ );
137
+ expect(await mgr.getToken()).toBe('abc');
138
+ });
139
+ });
140
+
141
+ describe('createOAuthAxios', () => {
142
+ it('retries the request with a refreshed token when the first call rejects with 401', async () => {
143
+ const { fetch } = countingFetcher();
144
+ const mgr = new TokenManager(fetch, 60, makeClock().now);
145
+ await mgr.getToken(); // seed token-1
146
+
147
+ const seenAuth: (string | undefined)[] = [];
148
+ let calls = 0;
149
+ const adapter: AxiosAdapter = async (config) => {
150
+ calls += 1;
151
+ seenAuth.push(config.headers?.Authorization as string | undefined);
152
+ if (calls === 1) {
153
+ // eslint-disable-next-line prefer-promise-reject-errors
154
+ return Promise.reject(
155
+ Object.assign(new Error('401'), {
156
+ isAxiosError: true,
157
+ config,
158
+ response: { data: {}, status: 401, statusText: 'Unauthorized', headers: {}, config },
159
+ }),
160
+ );
161
+ }
162
+ return { data: { ok: true }, status: 200, statusText: 'OK', headers: {}, config };
163
+ };
164
+ const http = createOAuthAxios(mgr, axios.create({ adapter }));
165
+
166
+ const response = await http.request({
167
+ url: 'http://localhost/v1/cards/x',
168
+ method: 'get',
169
+ headers: { Authorization: 'Bearer token-1' } as never,
170
+ });
171
+
172
+ expect(response.status).toBe(200);
173
+ expect(calls).toBe(2);
174
+ expect(seenAuth[0]).toBe('Bearer token-1');
175
+ expect(seenAuth[1]).toBe('Bearer token-2');
176
+ });
177
+
178
+ it('surfaces the error after a single retry (no infinite loop)', async () => {
179
+ const { fetch } = countingFetcher();
180
+ const mgr = new TokenManager(fetch, 60, makeClock().now);
181
+ await mgr.getToken();
182
+
183
+ let calls = 0;
184
+ const adapter: AxiosAdapter = async (config) => {
185
+ calls += 1;
186
+ return Promise.reject(
187
+ Object.assign(new Error('401'), {
188
+ isAxiosError: true,
189
+ config,
190
+ response: { data: {}, status: 401, statusText: 'Unauthorized', headers: {}, config },
191
+ }),
192
+ );
193
+ };
194
+ const http = createOAuthAxios(mgr, axios.create({ adapter }));
195
+
196
+ await expect(
197
+ http.request({
198
+ url: 'http://localhost/v1/cards/x',
199
+ method: 'get',
200
+ headers: { Authorization: 'Bearer token-1' } as never,
201
+ }),
202
+ ).rejects.toThrow();
203
+ expect(calls).toBe(2); // original + one retry only
204
+ });
205
+ });
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Wire-level tests for the pin API client, asserting the request against an
3
+ * exact JSON payload. A capturing axios adapter intercepts the request instead of
4
+ * hitting the network, so this exercises the real generated client (URL building,
5
+ * Content-Type, body serialization) without a live server or a mock library.
6
+ */
7
+ import axios, { type InternalAxiosRequestConfig } from 'axios';
8
+ import { describe, expect, it } from 'vitest';
9
+ import { PINOperationsUsingPKIApi } from '../src/pin';
10
+
11
+ function capturingClient() {
12
+ const captured: { config?: InternalAxiosRequestConfig } = {};
13
+ const instance = axios.create({
14
+ adapter: async (config) => {
15
+ captured.config = config;
16
+ return { data: undefined, status: 200, statusText: 'OK', headers: {}, config };
17
+ },
18
+ });
19
+ return { captured, instance };
20
+ }
21
+
22
+ describe('PINOperationsUsingPKIApi.viewPin', () => {
23
+ it('POSTs the exact view-pin JSON to the pin view endpoint', async () => {
24
+ const { captured, instance } = capturingClient();
25
+ const api = new PINOperationsUsingPKIApi(undefined, 'http://localhost', instance);
26
+
27
+ await api.viewPin({
28
+ pinControlId: '11111111-1111-1111-1111-111111111111',
29
+ pubKey: 'SYNTHETIC_PUBLIC_KEY',
30
+ });
31
+
32
+ expect(captured.config?.method?.toUpperCase()).toBe('POST');
33
+ expect(captured.config?.url).toBe('http://localhost/v1/pin/view');
34
+ expect(captured.config?.headers?.['Content-Type']).toBe('application/json');
35
+ expect(captured.config?.data).toBe(
36
+ '{"pinControlId":"11111111-1111-1111-1111-111111111111","pubKey":"SYNTHETIC_PUBLIC_KEY"}',
37
+ );
38
+ });
39
+ });
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Wire-level tests for the threeds-oob API client, asserting the request against an
3
+ * exact JSON payload. A capturing axios adapter intercepts the request instead of
4
+ * hitting the network, so this exercises the real generated client (URL building,
5
+ * Content-Type, body serialization) without a live server or a mock library.
6
+ */
7
+ import axios, { type InternalAxiosRequestConfig } from 'axios';
8
+ import { describe, expect, it } from 'vitest';
9
+ import {
10
+ OOBAuthenticationChallengeWebhookNotificationApi,
11
+ ThreeDsTransactionCategoryEnum,
12
+ ThreeDsTransactionDeviceChannelEnum,
13
+ } from '../src/threeds-oob';
14
+
15
+ function capturingClient() {
16
+ const captured: { config?: InternalAxiosRequestConfig } = {};
17
+ const instance = axios.create({
18
+ adapter: async (config) => {
19
+ captured.config = config;
20
+ return { data: undefined, status: 200, statusText: 'OK', headers: {}, config };
21
+ },
22
+ });
23
+ return { captured, instance };
24
+ }
25
+
26
+ describe('OOBAuthenticationChallengeWebhookNotificationApi.initiateAuthenticationChallenge', () => {
27
+ it('POSTs the exact challenge JSON to the OOB challenge initiate endpoint', async () => {
28
+ const { captured, instance } = capturingClient();
29
+ const api = new OOBAuthenticationChallengeWebhookNotificationApi(undefined, 'http://localhost', instance);
30
+
31
+ await api.initiateAuthenticationChallenge({
32
+ authenticationId: '11111111-1111-1111-1111-111111111111',
33
+ challengeId: '22222222-2222-2222-2222-222222222222',
34
+ cardholder: {
35
+ id: '33333333-3333-3333-3333-333333333333',
36
+ customerNumber: 'CUST-0001',
37
+ },
38
+ card: {
39
+ id: '44444444-4444-4444-4444-444444444444',
40
+ maskedPan: '512345******0000',
41
+ },
42
+ threeDsTransaction: {
43
+ transactionAmount: { amount: 1000, currency: 'EUR' },
44
+ category: ThreeDsTransactionCategoryEnum.Payment,
45
+ deviceChannel: ThreeDsTransactionDeviceChannelEnum.App,
46
+ processedDateTime: '2024-05-31T06:55:17Z',
47
+ },
48
+ merchant: {
49
+ name: 'Acme Shop',
50
+ country: 'FIN',
51
+ url: 'https://merchant.example',
52
+ },
53
+ });
54
+
55
+ expect(captured.config?.method?.toUpperCase()).toBe('POST');
56
+ expect(captured.config?.url).toBe('http://localhost/v1/3ds/oob/challenge/initiate');
57
+ expect(captured.config?.headers?.['Content-Type']).toBe('application/json');
58
+ expect(captured.config?.data).toBe(
59
+ '{"authenticationId":"11111111-1111-1111-1111-111111111111","challengeId":"22222222-2222-2222-2222-222222222222","cardholder":{"id":"33333333-3333-3333-3333-333333333333","customerNumber":"CUST-0001"},"card":{"id":"44444444-4444-4444-4444-444444444444","maskedPan":"512345******0000"},"threeDsTransaction":{"transactionAmount":{"amount":1000,"currency":"EUR"},"category":"PAYMENT","deviceChannel":"APP","processedDateTime":"2024-05-31T06:55:17Z"},"merchant":{"name":"Acme Shop","country":"FIN","url":"https://merchant.example"}}',
60
+ );
61
+ });
62
+
63
+ it('serializes the NON_PAYMENT category to the exact JSON body', async () => {
64
+ const { captured, instance } = capturingClient();
65
+ const api = new OOBAuthenticationChallengeWebhookNotificationApi(undefined, 'http://localhost', instance);
66
+
67
+ await api.initiateAuthenticationChallenge({
68
+ authenticationId: '55555555-5555-5555-5555-555555555555',
69
+ challengeId: '66666666-6666-6666-6666-666666666666',
70
+ cardholder: {
71
+ id: '77777777-7777-7777-7777-777777777777',
72
+ customerNumber: 'CUST-0002',
73
+ },
74
+ card: {
75
+ id: '88888888-8888-8888-8888-888888888888',
76
+ maskedPan: '512345******1111',
77
+ },
78
+ threeDsTransaction: {
79
+ transactionAmount: { amount: 2500, currency: 'EUR' },
80
+ category: ThreeDsTransactionCategoryEnum.NonPayment,
81
+ deviceChannel: ThreeDsTransactionDeviceChannelEnum.Browser,
82
+ processedDateTime: '2024-06-01T10:00:00Z',
83
+ },
84
+ });
85
+
86
+ expect(captured.config?.data).toBe(
87
+ '{"authenticationId":"55555555-5555-5555-5555-555555555555","challengeId":"66666666-6666-6666-6666-666666666666","cardholder":{"id":"77777777-7777-7777-7777-777777777777","customerNumber":"CUST-0002"},"card":{"id":"88888888-8888-8888-8888-888888888888","maskedPan":"512345******1111"},"threeDsTransaction":{"transactionAmount":{"amount":2500,"currency":"EUR"},"category":"NON_PAYMENT","deviceChannel":"BROWSER","processedDateTime":"2024-06-01T10:00:00Z"}}',
88
+ );
89
+ });
90
+ });
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Wire-level tests for the threeds API client, asserting the request against an
3
+ * exact JSON payload. A capturing axios adapter intercepts the request instead of
4
+ * hitting the network, so this exercises the real generated client (URL building,
5
+ * Content-Type, body serialization) without a live server or a mock library.
6
+ */
7
+ import axios, { type InternalAxiosRequestConfig } from 'axios';
8
+ import { describe, expect, it } from 'vitest';
9
+ import { ThreeDSApi, AuthenticationChallengeResultBodyResultEnum } from '../src/threeds';
10
+
11
+ function capturingClient() {
12
+ const captured: { config?: InternalAxiosRequestConfig } = {};
13
+ const instance = axios.create({
14
+ adapter: async (config) => {
15
+ captured.config = config;
16
+ return { data: undefined, status: 200, statusText: 'OK', headers: {}, config };
17
+ },
18
+ });
19
+ return { captured, instance };
20
+ }
21
+
22
+ describe('ThreeDSApi.handleAuthenticationChallengeResult', () => {
23
+ it('POSTs the exact challenge-result JSON to the OOB result endpoint', async () => {
24
+ const { captured, instance } = capturingClient();
25
+ const api = new ThreeDSApi(undefined, 'http://localhost', instance);
26
+
27
+ await api.handleAuthenticationChallengeResult({
28
+ authenticationId: '11111111-1111-1111-1111-111111111111',
29
+ challengeId: '22222222-2222-2222-2222-222222222222',
30
+ result: AuthenticationChallengeResultBodyResultEnum.Success,
31
+ });
32
+
33
+ expect(captured.config?.method?.toUpperCase()).toBe('POST');
34
+ expect(captured.config?.url).toBe('http://localhost/v1/3ds/challenge/oob/result');
35
+ expect(captured.config?.headers?.['Content-Type']).toBe('application/json');
36
+ expect(captured.config?.data).toBe(
37
+ '{"authenticationId":"11111111-1111-1111-1111-111111111111","challengeId":"22222222-2222-2222-2222-222222222222","result":"SUCCESS"}',
38
+ );
39
+ });
40
+
41
+ it('serializes the FAIL result to the exact JSON body', async () => {
42
+ const { captured, instance } = capturingClient();
43
+ const api = new ThreeDSApi(undefined, 'http://localhost', instance);
44
+
45
+ await api.handleAuthenticationChallengeResult({
46
+ authenticationId: '33333333-3333-3333-3333-333333333333',
47
+ challengeId: '44444444-4444-4444-4444-444444444444',
48
+ result: AuthenticationChallengeResultBodyResultEnum.Fail,
49
+ });
50
+
51
+ expect(captured.config?.data).toBe(
52
+ '{"authenticationId":"33333333-3333-3333-3333-333333333333","challengeId":"44444444-4444-4444-4444-444444444444","result":"FAIL"}',
53
+ );
54
+ });
55
+ });
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Wire-level tests for the wallet API client, asserting the request against an
3
+ * exact JSON payload. A capturing axios adapter intercepts the request instead of
4
+ * hitting the network, so this exercises the real generated client (URL building,
5
+ * Content-Type, body serialization) without a live server or a mock library.
6
+ */
7
+ import axios, { type InternalAxiosRequestConfig } from 'axios';
8
+ import { describe, expect, it } from 'vitest';
9
+ import {
10
+ PushCardsApi,
11
+ PushAccountsToTokenRequestorRequestIncludeAccountHolderDataEnum,
12
+ } from '../src/wallet';
13
+
14
+ function capturingClient() {
15
+ const captured: { config?: InternalAxiosRequestConfig } = {};
16
+ const instance = axios.create({
17
+ adapter: async (config) => {
18
+ captured.config = config;
19
+ return { data: undefined, status: 200, statusText: 'OK', headers: {}, config };
20
+ },
21
+ });
22
+ return { captured, instance };
23
+ }
24
+
25
+ describe('PushCardsApi.pushCardsToTokenRequestor', () => {
26
+ it('POSTs the exact push-cards JSON to the mdestokenconnect push endpoint', async () => {
27
+ const { captured, instance } = capturingClient();
28
+ const api = new PushCardsApi(undefined, 'http://localhost', instance);
29
+
30
+ await api.pushCardsToTokenRequestor({
31
+ tokenRequestorId: '11111111-1111-1111-1111-111111111111',
32
+ cardIds: ['22222222-2222-2222-2222-222222222222'],
33
+ includeAccountHolderData: [
34
+ PushAccountsToTokenRequestorRequestIncludeAccountHolderDataEnum.AllSupported,
35
+ ],
36
+ });
37
+
38
+ expect(captured.config?.method?.toUpperCase()).toBe('POST');
39
+ expect(captured.config?.url).toBe('http://localhost/v1/wallet/mdestokenconnect/push');
40
+ expect(captured.config?.headers?.['Content-Type']).toBe('application/json');
41
+ expect(captured.config?.data).toBe(
42
+ '{"tokenRequestorId":"11111111-1111-1111-1111-111111111111","cardIds":["22222222-2222-2222-2222-222222222222"],"includeAccountHolderData":["ALL_SUPPORTED"]}',
43
+ );
44
+ });
45
+
46
+ it('serializes the NAME account-holder-data enum to the exact JSON body', async () => {
47
+ const { captured, instance } = capturingClient();
48
+ const api = new PushCardsApi(undefined, 'http://localhost', instance);
49
+
50
+ await api.pushCardsToTokenRequestor({
51
+ tokenRequestorId: '33333333-3333-3333-3333-333333333333',
52
+ cardIds: ['44444444-4444-4444-4444-444444444444'],
53
+ includeAccountHolderData: [
54
+ PushAccountsToTokenRequestorRequestIncludeAccountHolderDataEnum.Name,
55
+ ],
56
+ });
57
+
58
+ expect(captured.config?.data).toBe(
59
+ '{"tokenRequestorId":"33333333-3333-3333-3333-333333333333","cardIds":["44444444-4444-4444-4444-444444444444"],"includeAccountHolderData":["NAME"]}',
60
+ );
61
+ });
62
+ });
@@ -0,0 +1,7 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "module": "esnext",
5
+ "outDir": "dist/esm"
6
+ }
7
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "compilerOptions": {
3
+ "declaration": true,
4
+ "target": "ES6",
5
+ "module": "commonjs",
6
+ "noImplicitAny": true,
7
+ "outDir": "dist",
8
+ "rootDir": "src",
9
+ "moduleResolution": "node",
10
+ "typeRoots": ["node_modules/@types"]
11
+ },
12
+ "include": ["src/**/*.ts"],
13
+ "exclude": ["dist", "node_modules"]
14
+ }