clearbank-sdk 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/LICENSE +21 -0
  3. package/README.md +295 -0
  4. package/dist/cjs/core/config.js +25 -0
  5. package/dist/cjs/core/config.js.map +1 -0
  6. package/dist/cjs/core/crypto.js +110 -0
  7. package/dist/cjs/core/crypto.js.map +1 -0
  8. package/dist/cjs/core/http.js +191 -0
  9. package/dist/cjs/core/http.js.map +1 -0
  10. package/dist/cjs/core/index.js +14 -0
  11. package/dist/cjs/core/index.js.map +1 -0
  12. package/dist/cjs/core/retry.js +42 -0
  13. package/dist/cjs/core/retry.js.map +1 -0
  14. package/dist/cjs/domains/accounts/index.js +6 -0
  15. package/dist/cjs/domains/accounts/index.js.map +1 -0
  16. package/dist/cjs/domains/accounts/service.js +216 -0
  17. package/dist/cjs/domains/accounts/service.js.map +1 -0
  18. package/dist/cjs/domains/accounts/types.js +3 -0
  19. package/dist/cjs/domains/accounts/types.js.map +1 -0
  20. package/dist/cjs/domains/embedded/index.js +6 -0
  21. package/dist/cjs/domains/embedded/index.js.map +1 -0
  22. package/dist/cjs/domains/embedded/service.js +215 -0
  23. package/dist/cjs/domains/embedded/service.js.map +1 -0
  24. package/dist/cjs/domains/embedded/types.js +3 -0
  25. package/dist/cjs/domains/embedded/types.js.map +1 -0
  26. package/dist/cjs/domains/multicurrency/index.js +6 -0
  27. package/dist/cjs/domains/multicurrency/index.js.map +1 -0
  28. package/dist/cjs/domains/multicurrency/service.js +202 -0
  29. package/dist/cjs/domains/multicurrency/service.js.map +1 -0
  30. package/dist/cjs/domains/multicurrency/types.js +3 -0
  31. package/dist/cjs/domains/multicurrency/types.js.map +1 -0
  32. package/dist/cjs/domains/payments/index.js +6 -0
  33. package/dist/cjs/domains/payments/index.js.map +1 -0
  34. package/dist/cjs/domains/payments/service.js +255 -0
  35. package/dist/cjs/domains/payments/service.js.map +1 -0
  36. package/dist/cjs/domains/payments/types.js +3 -0
  37. package/dist/cjs/domains/payments/types.js.map +1 -0
  38. package/dist/cjs/domains/webhooks/index.js +7 -0
  39. package/dist/cjs/domains/webhooks/index.js.map +1 -0
  40. package/dist/cjs/domains/webhooks/service.js +173 -0
  41. package/dist/cjs/domains/webhooks/service.js.map +1 -0
  42. package/dist/cjs/domains/webhooks/types.js +8 -0
  43. package/dist/cjs/domains/webhooks/types.js.map +1 -0
  44. package/dist/cjs/index.js +73 -0
  45. package/dist/cjs/index.js.map +1 -0
  46. package/dist/cjs/types/index.js +45 -0
  47. package/dist/cjs/types/index.js.map +1 -0
  48. package/dist/cjs/utils/index.js +46 -0
  49. package/dist/cjs/utils/index.js.map +1 -0
  50. package/dist/esm/core/config.js +22 -0
  51. package/dist/esm/core/config.js.map +1 -0
  52. package/dist/esm/core/crypto.js +105 -0
  53. package/dist/esm/core/crypto.js.map +1 -0
  54. package/dist/esm/core/http.js +187 -0
  55. package/dist/esm/core/http.js.map +1 -0
  56. package/dist/esm/core/index.js +5 -0
  57. package/dist/esm/core/index.js.map +1 -0
  58. package/dist/esm/core/retry.js +39 -0
  59. package/dist/esm/core/retry.js.map +1 -0
  60. package/dist/esm/domains/accounts/index.js +2 -0
  61. package/dist/esm/domains/accounts/index.js.map +1 -0
  62. package/dist/esm/domains/accounts/service.js +212 -0
  63. package/dist/esm/domains/accounts/service.js.map +1 -0
  64. package/dist/esm/domains/accounts/types.js +2 -0
  65. package/dist/esm/domains/accounts/types.js.map +1 -0
  66. package/dist/esm/domains/embedded/index.js +2 -0
  67. package/dist/esm/domains/embedded/index.js.map +1 -0
  68. package/dist/esm/domains/embedded/service.js +211 -0
  69. package/dist/esm/domains/embedded/service.js.map +1 -0
  70. package/dist/esm/domains/embedded/types.js +2 -0
  71. package/dist/esm/domains/embedded/types.js.map +1 -0
  72. package/dist/esm/domains/multicurrency/index.js +2 -0
  73. package/dist/esm/domains/multicurrency/index.js.map +1 -0
  74. package/dist/esm/domains/multicurrency/service.js +198 -0
  75. package/dist/esm/domains/multicurrency/service.js.map +1 -0
  76. package/dist/esm/domains/multicurrency/types.js +2 -0
  77. package/dist/esm/domains/multicurrency/types.js.map +1 -0
  78. package/dist/esm/domains/payments/index.js +2 -0
  79. package/dist/esm/domains/payments/index.js.map +1 -0
  80. package/dist/esm/domains/payments/service.js +251 -0
  81. package/dist/esm/domains/payments/service.js.map +1 -0
  82. package/dist/esm/domains/payments/types.js +2 -0
  83. package/dist/esm/domains/payments/types.js.map +1 -0
  84. package/dist/esm/domains/webhooks/index.js +2 -0
  85. package/dist/esm/domains/webhooks/index.js.map +1 -0
  86. package/dist/esm/domains/webhooks/service.js +168 -0
  87. package/dist/esm/domains/webhooks/service.js.map +1 -0
  88. package/dist/esm/domains/webhooks/types.js +5 -0
  89. package/dist/esm/domains/webhooks/types.js.map +1 -0
  90. package/dist/esm/index.js +56 -0
  91. package/dist/esm/index.js.map +1 -0
  92. package/dist/esm/types/index.js +41 -0
  93. package/dist/esm/types/index.js.map +1 -0
  94. package/dist/esm/utils/index.js +35 -0
  95. package/dist/esm/utils/index.js.map +1 -0
  96. package/dist/types/core/config.d.ts +34 -0
  97. package/dist/types/core/config.d.ts.map +1 -0
  98. package/dist/types/core/crypto.d.ts +20 -0
  99. package/dist/types/core/crypto.d.ts.map +1 -0
  100. package/dist/types/core/http.d.ts +34 -0
  101. package/dist/types/core/http.d.ts.map +1 -0
  102. package/dist/types/core/index.d.ts +7 -0
  103. package/dist/types/core/index.d.ts.map +1 -0
  104. package/dist/types/core/retry.d.ts +14 -0
  105. package/dist/types/core/retry.d.ts.map +1 -0
  106. package/dist/types/domains/accounts/index.d.ts +3 -0
  107. package/dist/types/domains/accounts/index.d.ts.map +1 -0
  108. package/dist/types/domains/accounts/service.d.ts +61 -0
  109. package/dist/types/domains/accounts/service.d.ts.map +1 -0
  110. package/dist/types/domains/accounts/types.d.ts +90 -0
  111. package/dist/types/domains/accounts/types.d.ts.map +1 -0
  112. package/dist/types/domains/embedded/index.d.ts +3 -0
  113. package/dist/types/domains/embedded/index.d.ts.map +1 -0
  114. package/dist/types/domains/embedded/service.d.ts +63 -0
  115. package/dist/types/domains/embedded/service.d.ts.map +1 -0
  116. package/dist/types/domains/embedded/types.d.ts +148 -0
  117. package/dist/types/domains/embedded/types.d.ts.map +1 -0
  118. package/dist/types/domains/multicurrency/index.d.ts +3 -0
  119. package/dist/types/domains/multicurrency/index.d.ts.map +1 -0
  120. package/dist/types/domains/multicurrency/service.d.ts +50 -0
  121. package/dist/types/domains/multicurrency/service.d.ts.map +1 -0
  122. package/dist/types/domains/multicurrency/types.d.ts +84 -0
  123. package/dist/types/domains/multicurrency/types.d.ts.map +1 -0
  124. package/dist/types/domains/payments/index.d.ts +3 -0
  125. package/dist/types/domains/payments/index.d.ts.map +1 -0
  126. package/dist/types/domains/payments/service.d.ts +65 -0
  127. package/dist/types/domains/payments/service.d.ts.map +1 -0
  128. package/dist/types/domains/payments/types.d.ts +107 -0
  129. package/dist/types/domains/payments/types.d.ts.map +1 -0
  130. package/dist/types/domains/webhooks/index.d.ts +3 -0
  131. package/dist/types/domains/webhooks/index.d.ts.map +1 -0
  132. package/dist/types/domains/webhooks/service.d.ts +66 -0
  133. package/dist/types/domains/webhooks/service.d.ts.map +1 -0
  134. package/dist/types/domains/webhooks/types.d.ts +215 -0
  135. package/dist/types/domains/webhooks/types.d.ts.map +1 -0
  136. package/dist/types/index.d.ts +54 -0
  137. package/dist/types/index.d.ts.map +1 -0
  138. package/dist/types/types/index.d.ts +77 -0
  139. package/dist/types/types/index.d.ts.map +1 -0
  140. package/dist/types/utils/index.d.ts +22 -0
  141. package/dist/types/utils/index.d.ts.map +1 -0
  142. package/package.json +96 -0
@@ -0,0 +1,173 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WebhooksService = exports.buildAckBody = void 0;
4
+ const crypto_js_1 = require("../../core/crypto.js");
5
+ const index_js_1 = require("../../types/index.js");
6
+ var types_js_1 = require("./types.js");
7
+ Object.defineProperty(exports, "buildAckBody", { enumerable: true, get: function () { return types_js_1.buildAckBody; } });
8
+ /**
9
+ * Webhook signature verification and typed event dispatch.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * const webhooks = client.webhooks;
14
+ *
15
+ * app.post('/webhooks', async (req, res) => {
16
+ * const body = JSON.stringify(req.body);
17
+ * const isValid = await webhooks.verifySignature(body, req.headers['digitalsignature'], publicKeyPem);
18
+ * if (!isValid) return res.status(401).send('Invalid signature');
19
+ *
20
+ * await webhooks.dispatch(req.body, {
21
+ * TransactionSettled: async (event) => {
22
+ * await processPayment(event);
23
+ * },
24
+ * onUnknown: (envelope) => console.log('Unknown event:', envelope.Type),
25
+ * });
26
+ *
27
+ * res.json(webhooks.buildAck(req.body));
28
+ * });
29
+ * ```
30
+ */
31
+ class WebhooksService {
32
+ /**
33
+ * Verifies a ClearBank `DigitalSignature` header using ClearBank's public key.
34
+ * Download the public key from Portal → Webhook Management.
35
+ *
36
+ * @param body Raw request body as a string (before JSON.parse).
37
+ * @param signature Value of the `DigitalSignature` header.
38
+ * @param publicKeyPem ClearBank RSA public key in PEM format.
39
+ */
40
+ async verifySignature(body, signature, publicKeyPem) {
41
+ return (0, crypto_js_1.verifySignature)(body, signature, publicKeyPem);
42
+ }
43
+ /**
44
+ * Parses and validates a raw webhook body into a typed envelope.
45
+ *
46
+ * @throws {ClearBankError} if the body is not valid JSON or is missing the Type field.
47
+ */
48
+ parseEnvelope(rawBody) {
49
+ let parsed;
50
+ if (typeof rawBody === 'string') {
51
+ try {
52
+ parsed = JSON.parse(rawBody);
53
+ }
54
+ catch {
55
+ throw new index_js_1.ClearBankError({
56
+ message: 'Webhook body is not valid JSON',
57
+ statusCode: null,
58
+ });
59
+ }
60
+ }
61
+ else {
62
+ parsed = rawBody;
63
+ }
64
+ if (!parsed || typeof parsed !== 'object') {
65
+ throw new index_js_1.ClearBankError({ message: 'Webhook body must be an object', statusCode: null });
66
+ }
67
+ const obj = parsed;
68
+ if (typeof obj['Type'] !== 'string' || !obj['Type']) {
69
+ throw new index_js_1.ClearBankError({
70
+ message: 'Webhook envelope missing Type field',
71
+ statusCode: null,
72
+ });
73
+ }
74
+ return {
75
+ Type: obj['Type'],
76
+ Version: typeof obj['Version'] === 'number' ? obj['Version'] : 0,
77
+ Nonce: typeof obj['Nonce'] === 'number' ? obj['Nonce'] : 0,
78
+ Payload: obj['Payload'] ?? {},
79
+ };
80
+ }
81
+ /**
82
+ * Parses the Payload of an envelope into a strongly-typed event object.
83
+ * Returns `null` for unknown event types (forward-compatible).
84
+ */
85
+ parseEvent(envelope, eventType) {
86
+ if (envelope.Type !== eventType)
87
+ return null;
88
+ return envelope.Payload;
89
+ }
90
+ /**
91
+ * Dispatches a webhook envelope to the appropriate handler.
92
+ *
93
+ * Only the handlers you provide are called — unhandled event types are silently
94
+ * ignored unless you provide `onUnknown`. This makes it easy to add handlers
95
+ * incrementally as you subscribe to more webhook event types.
96
+ *
97
+ * @param envelope Parsed webhook envelope (from `parseEnvelope`).
98
+ * @param handlers Object mapping event type names to handler functions.
99
+ */
100
+ async dispatch(envelope, handlers) {
101
+ const type = envelope.Type;
102
+ switch (type) {
103
+ case 'FITestEvent':
104
+ await handlers.FITestEvent?.(envelope.Payload, envelope);
105
+ break;
106
+ case 'TransactionSettled':
107
+ await handlers.TransactionSettled?.(envelope.Payload, envelope);
108
+ break;
109
+ case 'PaymentMessageAssessmentFailed':
110
+ await handlers.PaymentMessageAssessmentFailed?.(envelope.Payload, envelope);
111
+ break;
112
+ case 'PaymentMessageValidationFailed':
113
+ await handlers.PaymentMessageValidationFailed?.(envelope.Payload, envelope);
114
+ break;
115
+ case 'TransactionRejected':
116
+ await handlers.TransactionRejected?.(envelope.Payload, envelope);
117
+ break;
118
+ case 'FpsPaymentReturnCreated':
119
+ await handlers.FpsPaymentReturnCreated?.(envelope.Payload, envelope);
120
+ break;
121
+ case 'BacsPaymentCreated':
122
+ await handlers.BacsPaymentCreated?.(envelope.Payload, envelope);
123
+ break;
124
+ case 'BacsMandateCreated':
125
+ await handlers.BacsMandateCreated?.(envelope.Payload, envelope);
126
+ break;
127
+ case 'BacsMandateCancelled':
128
+ await handlers.BacsMandateCancelled?.(envelope.Payload, envelope);
129
+ break;
130
+ case 'BacsMandateMigrated':
131
+ await handlers.BacsMandateMigrated?.(envelope.Payload, envelope);
132
+ break;
133
+ case 'ChapsPaymentCreated':
134
+ await handlers.ChapsPaymentCreated?.(envelope.Payload, envelope);
135
+ break;
136
+ case 'ChapsReturnCreated':
137
+ await handlers.ChapsReturnCreated?.(envelope.Payload, envelope);
138
+ break;
139
+ case 'CopOutboundResponse':
140
+ await handlers.CopOutboundResponse?.(envelope.Payload, envelope);
141
+ break;
142
+ case 'MccyTransactionCreated':
143
+ await handlers.MccyTransactionCreated?.(envelope.Payload, envelope);
144
+ break;
145
+ case 'FxTradeCreated':
146
+ await handlers.FxTradeCreated?.(envelope.Payload, envelope);
147
+ break;
148
+ case 'FxTradeSettled':
149
+ await handlers.FxTradeSettled?.(envelope.Payload, envelope);
150
+ break;
151
+ case 'CustomerKycStatusChanged':
152
+ await handlers.CustomerKycStatusChanged?.(envelope.Payload, envelope);
153
+ break;
154
+ case 'EmbeddedAccountCreated':
155
+ await handlers.EmbeddedAccountCreated?.(envelope.Payload, envelope);
156
+ break;
157
+ case 'EmbeddedTransactionSettled':
158
+ await handlers.EmbeddedTransactionSettled?.(envelope.Payload, envelope);
159
+ break;
160
+ default:
161
+ await handlers.onUnknown?.(envelope);
162
+ }
163
+ }
164
+ /**
165
+ * Builds the JSON acknowledgement body to send in the webhook response.
166
+ * ClearBank uses the nonce to track delivered events.
167
+ */
168
+ buildAck(envelope) {
169
+ return { nonce: envelope.Nonce };
170
+ }
171
+ }
172
+ exports.WebhooksService = WebhooksService;
173
+ //# sourceMappingURL=service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.js","sourceRoot":"","sources":["../../../../src/domains/webhooks/service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildAckBody = buildAckBody;
4
+ /** Returns the JSON body to send as the webhook acknowledgement. */
5
+ function buildAckBody(envelope) {
6
+ return { nonce: envelope.Nonce };
7
+ }
8
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/domains/webhooks/types.ts"],"names":[],"mappings":";;AAwCA,oCAEC;AAHD,oEAAoE;AACpE,SAAgB,YAAY,CAAC,QAAyB;IACpD,OAAO,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,CAAC;AACnC,CAAC"}
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ /**
3
+ * clearbank-sdk — Production-grade TypeScript SDK for the ClearBank UK API.
4
+ *
5
+ * @packageDocumentation
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.ClearBankClient = exports.formatAmount = exports.isValidIBAN = exports.isValidAccountNumber = exports.isValidSortCode = exports.isUUID = exports.generateUUID = exports.buildAckBody = exports.WebhooksService = exports.EmbeddedBankingService = exports.MultiCurrencyService = exports.PaymentsService = exports.AccountsService = exports.ClearBankError = void 0;
9
+ const http_js_1 = require("./core/http.js");
10
+ const config_js_1 = require("./core/config.js");
11
+ const service_js_1 = require("./domains/accounts/service.js");
12
+ const service_js_2 = require("./domains/payments/service.js");
13
+ const service_js_3 = require("./domains/multicurrency/service.js");
14
+ const service_js_4 = require("./domains/embedded/service.js");
15
+ const service_js_5 = require("./domains/webhooks/service.js");
16
+ var index_js_1 = require("./types/index.js");
17
+ Object.defineProperty(exports, "ClearBankError", { enumerable: true, get: function () { return index_js_1.ClearBankError; } });
18
+ // Domain services
19
+ var service_js_6 = require("./domains/accounts/service.js");
20
+ Object.defineProperty(exports, "AccountsService", { enumerable: true, get: function () { return service_js_6.AccountsService; } });
21
+ var service_js_7 = require("./domains/payments/service.js");
22
+ Object.defineProperty(exports, "PaymentsService", { enumerable: true, get: function () { return service_js_7.PaymentsService; } });
23
+ var service_js_8 = require("./domains/multicurrency/service.js");
24
+ Object.defineProperty(exports, "MultiCurrencyService", { enumerable: true, get: function () { return service_js_8.MultiCurrencyService; } });
25
+ var service_js_9 = require("./domains/embedded/service.js");
26
+ Object.defineProperty(exports, "EmbeddedBankingService", { enumerable: true, get: function () { return service_js_9.EmbeddedBankingService; } });
27
+ var service_js_10 = require("./domains/webhooks/service.js");
28
+ Object.defineProperty(exports, "WebhooksService", { enumerable: true, get: function () { return service_js_10.WebhooksService; } });
29
+ var service_js_11 = require("./domains/webhooks/service.js");
30
+ Object.defineProperty(exports, "buildAckBody", { enumerable: true, get: function () { return service_js_11.buildAckBody; } });
31
+ // Utilities
32
+ var index_js_2 = require("./utils/index.js");
33
+ Object.defineProperty(exports, "generateUUID", { enumerable: true, get: function () { return index_js_2.generateUUID; } });
34
+ Object.defineProperty(exports, "isUUID", { enumerable: true, get: function () { return index_js_2.isUUID; } });
35
+ Object.defineProperty(exports, "isValidSortCode", { enumerable: true, get: function () { return index_js_2.isValidSortCode; } });
36
+ Object.defineProperty(exports, "isValidAccountNumber", { enumerable: true, get: function () { return index_js_2.isValidAccountNumber; } });
37
+ Object.defineProperty(exports, "isValidIBAN", { enumerable: true, get: function () { return index_js_2.isValidIBAN; } });
38
+ Object.defineProperty(exports, "formatAmount", { enumerable: true, get: function () { return index_js_2.formatAmount; } });
39
+ // ---------------------------------------------------------------------------
40
+ // ClearBankClient
41
+ // ---------------------------------------------------------------------------
42
+ /**
43
+ * The top-level ClearBank API client.
44
+ *
45
+ * @example
46
+ * ```ts
47
+ * const client = new ClearBankClient({
48
+ * apiToken: process.env.CLEARBANK_API_TOKEN!,
49
+ * privateKey: process.env.CLEARBANK_PRIVATE_KEY!,
50
+ * environment: 'simulation',
51
+ * });
52
+ *
53
+ * const accounts = await client.accounts.list();
54
+ * await client.payments.sendFPS({ accountId, payment: { ... } });
55
+ * ```
56
+ */
57
+ class ClearBankClient {
58
+ constructor(config) {
59
+ const resolved = (0, config_js_1.resolveConfig)(config);
60
+ const http = new http_js_1.HttpClient(resolved);
61
+ this.accounts = new service_js_1.AccountsService(http);
62
+ this.payments = new service_js_2.PaymentsService(http);
63
+ this.multiCurrency = new service_js_3.MultiCurrencyService(http);
64
+ this.embedded = new service_js_4.EmbeddedBankingService(http);
65
+ this.webhooks = new service_js_5.WebhooksService();
66
+ }
67
+ static generateRequestId() {
68
+ return http_js_1.HttpClient.generateRequestId();
69
+ }
70
+ }
71
+ exports.ClearBankClient = ClearBankClient;
72
+ exports.default = ClearBankClient;
73
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAEH,4CAA4C;AAC5C,gDAAiD;AACjD,8DAAgE;AAChE,8DAAgE;AAChE,mEAA0E;AAC1E,8DAAuE;AACvE,8DAAgE;AAMhE,6CAAkD;AAAzC,0GAAA,cAAc,OAAA;AAgBvB,kBAAkB;AAClB,4DAAgE;AAAvD,6GAAA,eAAe,OAAA;AAkBxB,4DAAgE;AAAvD,6GAAA,eAAe,OAAA;AAoBxB,iEAA0E;AAAjE,kHAAA,oBAAoB,OAAA;AAgB7B,4DAAuE;AAA9D,oHAAA,sBAAsB,OAAA;AA0B/B,6DAAgE;AAAvD,8GAAA,eAAe,OAAA;AACxB,6DAA6D;AAApD,2GAAA,YAAY,OAAA;AA6BrB,YAAY;AACZ,6CAO0B;AANxB,wGAAA,YAAY,OAAA;AACZ,kGAAA,MAAM,OAAA;AACN,2GAAA,eAAe,OAAA;AACf,gHAAA,oBAAoB,OAAA;AACpB,uGAAA,WAAW,OAAA;AACX,wGAAA,YAAY,OAAA;AAGd,8EAA8E;AAC9E,kBAAkB;AAClB,8EAA8E;AAE9E;;;;;;;;;;;;;;GAcG;AACH,MAAa,eAAe;IAO1B,YAAY,MAAuB;QACjC,MAAM,QAAQ,GAAG,IAAA,yBAAa,EAAC,MAAM,CAAC,CAAC;QACvC,MAAM,IAAI,GAAG,IAAI,oBAAU,CAAC,QAAQ,CAAC,CAAC;QAEtC,IAAI,CAAC,QAAQ,GAAG,IAAI,4BAAe,CAAC,IAAI,CAAC,CAAC;QAC1C,IAAI,CAAC,QAAQ,GAAG,IAAI,4BAAe,CAAC,IAAI,CAAC,CAAC;QAC1C,IAAI,CAAC,aAAa,GAAG,IAAI,iCAAoB,CAAC,IAAI,CAAC,CAAC;QACpD,IAAI,CAAC,QAAQ,GAAG,IAAI,mCAAsB,CAAC,IAAI,CAAC,CAAC;QACjD,IAAI,CAAC,QAAQ,GAAG,IAAI,4BAAe,EAAE,CAAC;IACxC,CAAC;IAED,MAAM,CAAC,iBAAiB;QACtB,OAAO,oBAAU,CAAC,iBAAiB,EAAE,CAAC;IACxC,CAAC;CACF;AArBD,0CAqBC;AAED,kBAAe,eAAe,CAAC"}
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ /**
3
+ * Core types shared across the ClearBank SDK.
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ClearBankError = void 0;
7
+ class ClearBankError extends Error {
8
+ constructor(params) {
9
+ super(params.message);
10
+ this.name = 'ClearBankError';
11
+ this.statusCode = params.statusCode ?? null;
12
+ this.code = params.code ?? null;
13
+ this.correlationId = params.correlationId ?? null;
14
+ this.requestId = params.requestId ?? null;
15
+ this.details = params.details ?? null;
16
+ this.retryAfterSeconds = params.retryAfterSeconds ?? null;
17
+ // Maintain proper prototype chain
18
+ Object.setPrototypeOf(this, ClearBankError.prototype);
19
+ }
20
+ isNotFound() {
21
+ return this.statusCode === 404;
22
+ }
23
+ isConflict() {
24
+ return this.statusCode === 409;
25
+ }
26
+ isRateLimited() {
27
+ return this.statusCode === 429;
28
+ }
29
+ isUnprocessable() {
30
+ return this.statusCode === 422;
31
+ }
32
+ isRetryable() {
33
+ return this.statusCode === 429 || this.statusCode === 500 || this.statusCode === 503;
34
+ }
35
+ toString() {
36
+ let msg = `ClearBankError [${this.statusCode ?? 'network'}]: ${this.message}`;
37
+ if (this.correlationId)
38
+ msg += ` (X-Correlation-Id: ${this.correlationId})`;
39
+ if (this.retryAfterSeconds)
40
+ msg += ` (retry after ${this.retryAfterSeconds}s)`;
41
+ return msg;
42
+ }
43
+ }
44
+ exports.ClearBankError = ClearBankError;
45
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/types/index.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAUH,MAAa,cAAe,SAAQ,KAAK;IAQvC,YAAY,MAQX;QACC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACtB,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;QAC7B,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,IAAI,IAAI,CAAC;QAC5C,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,IAAI,IAAI,CAAC;QAChC,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC,aAAa,IAAI,IAAI,CAAC;QAClD,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,IAAI,IAAI,CAAC;QAC1C,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,IAAI,CAAC;QACtC,IAAI,CAAC,iBAAiB,GAAG,MAAM,CAAC,iBAAiB,IAAI,IAAI,CAAC;QAC1D,kCAAkC;QAClC,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,cAAc,CAAC,SAAS,CAAC,CAAC;IACxD,CAAC;IAED,UAAU;QACR,OAAO,IAAI,CAAC,UAAU,KAAK,GAAG,CAAC;IACjC,CAAC;IACD,UAAU;QACR,OAAO,IAAI,CAAC,UAAU,KAAK,GAAG,CAAC;IACjC,CAAC;IACD,aAAa;QACX,OAAO,IAAI,CAAC,UAAU,KAAK,GAAG,CAAC;IACjC,CAAC;IACD,eAAe;QACb,OAAO,IAAI,CAAC,UAAU,KAAK,GAAG,CAAC;IACjC,CAAC;IACD,WAAW;QACT,OAAO,IAAI,CAAC,UAAU,KAAK,GAAG,IAAI,IAAI,CAAC,UAAU,KAAK,GAAG,IAAI,IAAI,CAAC,UAAU,KAAK,GAAG,CAAC;IACvF,CAAC;IAEQ,QAAQ;QACf,IAAI,GAAG,GAAG,mBAAmB,IAAI,CAAC,UAAU,IAAI,SAAS,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QAC9E,IAAI,IAAI,CAAC,aAAa;YAAE,GAAG,IAAI,uBAAuB,IAAI,CAAC,aAAa,GAAG,CAAC;QAC5E,IAAI,IAAI,CAAC,iBAAiB;YAAE,GAAG,IAAI,iBAAiB,IAAI,CAAC,iBAAiB,IAAI,CAAC;QAC/E,OAAO,GAAG,CAAC;IACb,CAAC;CACF;AAnDD,wCAmDC"}
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports._HttpClient = exports.HttpClient = exports.generateUUID = void 0;
4
+ exports.isUUID = isUUID;
5
+ exports.isValidSortCode = isValidSortCode;
6
+ exports.isValidAccountNumber = isValidAccountNumber;
7
+ exports.isValidIBAN = isValidIBAN;
8
+ exports.formatAmount = formatAmount;
9
+ var crypto_js_1 = require("../core/crypto.js");
10
+ Object.defineProperty(exports, "generateUUID", { enumerable: true, get: function () { return crypto_js_1.generateUUID; } });
11
+ var http_js_1 = require("../core/http.js");
12
+ Object.defineProperty(exports, "HttpClient", { enumerable: true, get: function () { return http_js_1.HttpClient; } });
13
+ /** Returns true if a given string is a valid UUID v4 format. */
14
+ function isUUID(value) {
15
+ return /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);
16
+ }
17
+ /** Returns true if a string looks like a UK sort code (6 digits). */
18
+ function isValidSortCode(value) {
19
+ return /^\d{6}$/.test(value);
20
+ }
21
+ /** Returns true if a string looks like a UK account number (8 digits). */
22
+ function isValidAccountNumber(value) {
23
+ return /^\d{8}$/.test(value);
24
+ }
25
+ /** Returns true if a string looks like a valid IBAN. */
26
+ function isValidIBAN(value) {
27
+ return /^[A-Z]{2}\d{2}[A-Z0-9]{1,30}$/.test(value);
28
+ }
29
+ /**
30
+ * Formats a decimal amount string for display.
31
+ *
32
+ * @example formatAmount('1234.5', 'GBP') // '£1,234.50'
33
+ */
34
+ function formatAmount(amount, currency, locale = 'en-GB') {
35
+ const num = parseFloat(amount);
36
+ if (isNaN(num))
37
+ return amount;
38
+ return new Intl.NumberFormat(locale, { style: 'currency', currency }).format(num);
39
+ }
40
+ /**
41
+ * Generates a pre-flight X-Request-Id for idempotent retries.
42
+ * Store this before sending — use the same ID when retrying on 5XX.
43
+ */
44
+ var http_js_2 = require("../core/http.js");
45
+ Object.defineProperty(exports, "_HttpClient", { enumerable: true, get: function () { return http_js_2.HttpClient; } });
46
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/utils/index.ts"],"names":[],"mappings":";;;AAIA,wBAEC;AAGD,0CAEC;AAGD,oDAEC;AAGD,kCAEC;AAOD,oCAIC;AAhCD,+CAAiD;AAAxC,yGAAA,YAAY,OAAA;AACrB,2CAA6C;AAApC,qGAAA,UAAU,OAAA;AAEnB,gEAAgE;AAChE,SAAgB,MAAM,CAAC,KAAa;IAClC,OAAO,wEAAwE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC9F,CAAC;AAED,qEAAqE;AACrE,SAAgB,eAAe,CAAC,KAAa;IAC3C,OAAO,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC/B,CAAC;AAED,0EAA0E;AAC1E,SAAgB,oBAAoB,CAAC,KAAa;IAChD,OAAO,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC/B,CAAC;AAED,wDAAwD;AACxD,SAAgB,WAAW,CAAC,KAAa;IACvC,OAAO,+BAA+B,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACrD,CAAC;AAED;;;;GAIG;AACH,SAAgB,YAAY,CAAC,MAAc,EAAE,QAAgB,EAAE,MAAM,GAAG,OAAO;IAC7E,MAAM,GAAG,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;IAC/B,IAAI,KAAK,CAAC,GAAG,CAAC;QAAE,OAAO,MAAM,CAAC;IAC9B,OAAO,IAAI,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AACpF,CAAC;AAED;;;GAGG;AACH,2CAA4D;AAAnD,sGAAA,UAAU,OAAe"}
@@ -0,0 +1,22 @@
1
+ const BASE_URLS = {
2
+ simulation: 'https://institution-api-sim.clearbank.co.uk',
3
+ production: 'https://institution-api.clearbank.co.uk',
4
+ };
5
+ export function resolveConfig(config) {
6
+ if (!config.apiToken || config.apiToken.trim() === '') {
7
+ throw new Error('ClearBank SDK: apiToken is required and must not be empty.');
8
+ }
9
+ const environment = config.environment ?? 'simulation';
10
+ const baseUrl = config.baseUrl ?? BASE_URLS[environment];
11
+ return {
12
+ apiToken: config.apiToken,
13
+ privateKey: config.privateKey ?? null,
14
+ baseUrl,
15
+ timeoutMs: config.timeoutMs ?? 30000,
16
+ maxRetries: config.maxRetries ?? 3,
17
+ retryBaseDelayMs: config.retryBaseDelayMs ?? 1000,
18
+ retryMaxDelayMs: config.retryMaxDelayMs ?? 30000,
19
+ telemetryHook: config.telemetryHook ?? null,
20
+ };
21
+ }
22
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/core/config.ts"],"names":[],"mappings":"AAIA,MAAM,SAAS,GAAgC;IAC7C,UAAU,EAAE,6CAA6C;IACzD,UAAU,EAAE,yCAAyC;CAC7C,CAAC;AAkCX,MAAM,UAAU,aAAa,CAAC,MAAuB;IACnD,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QACtD,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC,CAAC;IAChF,CAAC;IAED,MAAM,WAAW,GAAgB,MAAM,CAAC,WAAW,IAAI,YAAY,CAAC;IACpE,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,SAAS,CAAC,WAAW,CAAC,CAAC;IAEzD,OAAO;QACL,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,IAAI;QACrC,OAAO;QACP,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,KAAM;QACrC,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,CAAC;QAClC,gBAAgB,EAAE,MAAM,CAAC,gBAAgB,IAAI,IAAK;QAClD,eAAe,EAAE,MAAM,CAAC,eAAe,IAAI,KAAM;QACjD,aAAa,EAAE,MAAM,CAAC,aAAa,IAAI,IAAI;KAC5C,CAAC;AACJ,CAAC"}
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Cryptographic utilities for the ClearBank SDK.
3
+ *
4
+ * Uses the Web Crypto API (globally available in Node.js ≥ 18 and all modern browsers).
5
+ * A Node.js `crypto` module fallback handles PKCS#1 RSA private keys.
6
+ */
7
+ /**
8
+ * Generates a UUID v4 string using cryptographically secure random bytes.
9
+ */
10
+ export function generateUUID() {
11
+ if (typeof globalThis.crypto?.randomUUID === 'function') {
12
+ return globalThis.crypto.randomUUID();
13
+ }
14
+ const bytes = new Uint8Array(16);
15
+ globalThis.crypto.getRandomValues(bytes);
16
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
17
+ bytes[6] = (bytes[6] & 0x0f) | 0x40;
18
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
19
+ bytes[8] = (bytes[8] & 0x3f) | 0x80;
20
+ const hex = Array.from(bytes).map((b) => b.toString(16).padStart(2, '0'));
21
+ return [
22
+ hex.slice(0, 4).join(''),
23
+ hex.slice(4, 6).join(''),
24
+ hex.slice(6, 8).join(''),
25
+ hex.slice(8, 10).join(''),
26
+ hex.slice(10, 16).join(''),
27
+ ].join('-');
28
+ }
29
+ /**
30
+ * Signs a request body with an RSA private key (PKCS#1 v1.5 + SHA-256).
31
+ * Returns Base64-encoded signature for the `DigitalSignature` header.
32
+ */
33
+ export async function signRequestBody(body, privateKeyPem) {
34
+ const cryptoKey = await importRsaPrivateKey(privateKeyPem);
35
+ const bodyBytes = toArrayBuffer(new TextEncoder().encode(body));
36
+ const signature = await globalThis.crypto.subtle.sign({ name: 'RSASSA-PKCS1-v1_5' }, cryptoKey, bodyBytes);
37
+ return bytesToBase64(new Uint8Array(signature));
38
+ }
39
+ /**
40
+ * Verifies a ClearBank `DigitalSignature` against the raw body using their RSA public key.
41
+ */
42
+ export async function verifySignature(body, signatureBase64, publicKeyPem) {
43
+ const cryptoKey = await importRsaPublicKey(publicKeyPem);
44
+ const bodyBytes = typeof body === 'string' ? toArrayBuffer(new TextEncoder().encode(body)) : toArrayBuffer(body);
45
+ const sigBytes = toArrayBuffer(base64ToUint8Array(signatureBase64));
46
+ return globalThis.crypto.subtle.verify({ name: 'RSASSA-PKCS1-v1_5' }, cryptoKey, sigBytes, bodyBytes);
47
+ }
48
+ // ---------------------------------------------------------------------------
49
+ // Private helpers
50
+ // ---------------------------------------------------------------------------
51
+ async function importRsaPrivateKey(pem) {
52
+ try {
53
+ const der = pemToDer(pem);
54
+ return await globalThis.crypto.subtle.importKey('pkcs8', der, { name: 'RSASSA-PKCS1-v1_5', hash: 'SHA-256' }, false, ['sign']);
55
+ }
56
+ catch {
57
+ // Fall back to Node.js crypto for PKCS#1 (BEGIN RSA PRIVATE KEY)
58
+ return importPkcs1ViaNode(pem);
59
+ }
60
+ }
61
+ async function importRsaPublicKey(pem) {
62
+ const der = pemToDer(pem);
63
+ return globalThis.crypto.subtle.importKey('spki', der, { name: 'RSASSA-PKCS1-v1_5', hash: 'SHA-256' }, false, ['verify']);
64
+ }
65
+ /** Strips PEM headers and returns a plain ArrayBuffer. */
66
+ function pemToDer(pem) {
67
+ const stripped = pem
68
+ .split('\n')
69
+ .filter((line) => !line.startsWith('-----'))
70
+ .join('');
71
+ return toArrayBuffer(base64ToUint8Array(stripped));
72
+ }
73
+ /**
74
+ * Copies a Uint8Array into a fresh ArrayBuffer.
75
+ * Required because TypeScript's Web Crypto types expect a plain ArrayBuffer,
76
+ * not an ArrayBufferLike (which includes SharedArrayBuffer).
77
+ */
78
+ function toArrayBuffer(bytes) {
79
+ const buf = new ArrayBuffer(bytes.byteLength);
80
+ new Uint8Array(buf).set(bytes);
81
+ return buf;
82
+ }
83
+ /** Decodes a Base64 string to a Uint8Array. */
84
+ function base64ToUint8Array(b64) {
85
+ const binary = atob(b64);
86
+ const bytes = new Uint8Array(binary.length);
87
+ for (let i = 0; i < binary.length; i++) {
88
+ bytes[i] = binary.charCodeAt(i);
89
+ }
90
+ return bytes;
91
+ }
92
+ /** Encodes a Uint8Array to a Base64 string. */
93
+ function bytesToBase64(bytes) {
94
+ return btoa(Array.from(bytes, (b) => String.fromCharCode(b)).join(''));
95
+ }
96
+ /** Node.js fallback: convert PKCS#1 PEM to Web CryptoKey via the `crypto` built-in. */
97
+ async function importPkcs1ViaNode(pem) {
98
+ const { createPrivateKey } = await import('node:crypto');
99
+ const nodeKey = createPrivateKey(pem);
100
+ const pkcs8Buffer = nodeKey.export({ type: 'pkcs8', format: 'der' });
101
+ // Slice into a plain ArrayBuffer to satisfy Web Crypto's strict BufferSource constraint.
102
+ const der = pkcs8Buffer.buffer.slice(pkcs8Buffer.byteOffset, pkcs8Buffer.byteOffset + pkcs8Buffer.byteLength);
103
+ return globalThis.crypto.subtle.importKey('pkcs8', der, { name: 'RSASSA-PKCS1-v1_5', hash: 'SHA-256' }, false, ['sign']);
104
+ }
105
+ //# sourceMappingURL=crypto.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crypto.js","sourceRoot":"","sources":["../../../src/core/crypto.ts"],"names":[],"mappings":"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"}