swapped-commerce-sdk 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,340 @@
1
+ // src/utils/errors.ts
2
+ class SwappedError extends Error {
3
+ statusCode;
4
+ code;
5
+ details;
6
+ constructor(message, statusCode, code, details) {
7
+ super(message);
8
+ this.name = "SwappedError";
9
+ this.statusCode = statusCode;
10
+ this.code = code;
11
+ this.details = details;
12
+ if (Error.captureStackTrace) {
13
+ Error.captureStackTrace(this, SwappedError);
14
+ }
15
+ }
16
+ }
17
+
18
+ class SwappedAuthenticationError extends SwappedError {
19
+ constructor(message = "Authentication failed") {
20
+ super(message, 401, "AUTHENTICATION_ERROR");
21
+ this.name = "SwappedAuthenticationError";
22
+ }
23
+ }
24
+
25
+ class SwappedValidationError extends SwappedError {
26
+ constructor(message, details) {
27
+ super(message, 400, "VALIDATION_ERROR", details);
28
+ this.name = "SwappedValidationError";
29
+ }
30
+ }
31
+
32
+ class SwappedRateLimitError extends SwappedError {
33
+ constructor(message = "Rate limit exceeded") {
34
+ super(message, 429, "RATE_LIMIT_ERROR");
35
+ this.name = "SwappedRateLimitError";
36
+ }
37
+ }
38
+
39
+ class SwappedNotFoundError extends SwappedError {
40
+ constructor(resource) {
41
+ super(`${resource} not found`, 404, "NOT_FOUND_ERROR");
42
+ this.name = "SwappedNotFoundError";
43
+ }
44
+ }
45
+ function createAuthenticationError(message) {
46
+ return new SwappedAuthenticationError(message);
47
+ }
48
+ function createValidationError(message, details) {
49
+ return new SwappedValidationError(message, details);
50
+ }
51
+ function createRateLimitError(message) {
52
+ return new SwappedRateLimitError(message);
53
+ }
54
+ function createNotFoundError(resource) {
55
+ return new SwappedNotFoundError(resource);
56
+ }
57
+
58
+ // src/utils/retry.ts
59
+ async function withRetry(fn, config) {
60
+ let lastError;
61
+ for (let attempt = 0;attempt <= config.maxRetries; attempt++) {
62
+ try {
63
+ return await fn();
64
+ } catch (error) {
65
+ lastError = error;
66
+ if (error instanceof SwappedError && error.statusCode !== undefined && error.statusCode >= 400 && error.statusCode < 500 && error.statusCode !== 429) {
67
+ throw error;
68
+ }
69
+ if (attempt < config.maxRetries) {
70
+ const delayMs = Math.pow(2, attempt) * 1000;
71
+ await delay(delayMs);
72
+ }
73
+ }
74
+ }
75
+ throw lastError ?? new Error("Request failed after retries");
76
+ }
77
+ function delay(ms) {
78
+ return new Promise((resolve) => setTimeout(resolve, ms));
79
+ }
80
+
81
+ // src/utils/http.ts
82
+ var BASE_URL = "https://pay-api.swapped.com";
83
+ function buildUrl(baseUrl, path, params) {
84
+ const url = new URL(path, baseUrl);
85
+ if (params) {
86
+ for (const [key, value] of Object.entries(params)) {
87
+ if (value !== undefined && value !== null) {
88
+ url.searchParams.append(key, String(value));
89
+ }
90
+ }
91
+ }
92
+ return url.toString();
93
+ }
94
+ function createRequestConfig(config, method, path, body) {
95
+ const headers = {
96
+ "X-API-Key": config.apiKey,
97
+ "Content-Type": "application/json",
98
+ Accept: "application/json"
99
+ };
100
+ const requestInit = {
101
+ method,
102
+ headers
103
+ };
104
+ if (body !== undefined) {
105
+ requestInit.body = JSON.stringify(body);
106
+ }
107
+ return requestInit;
108
+ }
109
+ async function handleErrorResponse(response) {
110
+ let errorData = {};
111
+ try {
112
+ const text = await response.text();
113
+ if (text) {
114
+ errorData = JSON.parse(text);
115
+ }
116
+ } catch {}
117
+ const message = errorData.message ?? response.statusText;
118
+ switch (response.status) {
119
+ case 401:
120
+ return new SwappedAuthenticationError(message);
121
+ case 400:
122
+ return new SwappedValidationError(message, errorData.details);
123
+ case 404:
124
+ return new SwappedNotFoundError(message);
125
+ case 429:
126
+ return new SwappedRateLimitError(message);
127
+ default:
128
+ return new SwappedError(message, response.status, errorData.code, errorData.details);
129
+ }
130
+ }
131
+ async function request(config, method, path, options) {
132
+ const url = buildUrl(BASE_URL, path, options?.params);
133
+ const requestConfig = createRequestConfig(config, method, path, options?.body);
134
+ const controller = new AbortController;
135
+ const timeoutId = setTimeout(() => {
136
+ controller.abort();
137
+ }, config.timeout);
138
+ try {
139
+ const response = await withRetry(async () => {
140
+ const res = await fetch(url, {
141
+ ...requestConfig,
142
+ signal: controller.signal
143
+ });
144
+ if (!res.ok) {
145
+ throw await handleErrorResponse(res);
146
+ }
147
+ return res;
148
+ }, {
149
+ maxRetries: config.retries,
150
+ timeout: config.timeout
151
+ });
152
+ const data = await response.json();
153
+ return data;
154
+ } catch (error) {
155
+ if (error instanceof SwappedError) {
156
+ throw error;
157
+ }
158
+ if (error instanceof Error && error.name === "AbortError") {
159
+ throw new SwappedError(`Request timeout after ${config.timeout}ms`, 408, "TIMEOUT_ERROR");
160
+ }
161
+ throw new SwappedError(error instanceof Error ? error.message : "Network error occurred", 0, "NETWORK_ERROR");
162
+ } finally {
163
+ clearTimeout(timeoutId);
164
+ }
165
+ }
166
+
167
+ // src/resources/orders.ts
168
+ async function listOrders(httpConfig, params) {
169
+ return request(httpConfig.config, "GET", "/v1/orders", {
170
+ params
171
+ });
172
+ }
173
+ async function getOrder(httpConfig, orderId) {
174
+ return request(httpConfig.config, "GET", `/v1/orders/${encodeURIComponent(orderId)}`);
175
+ }
176
+ async function refundOrder(httpConfig, orderId, params) {
177
+ return request(httpConfig.config, "POST", `/v1/merchants/orders/${encodeURIComponent(orderId)}/refund`, {
178
+ body: params
179
+ });
180
+ }
181
+
182
+ // src/resources/paymentLinks.ts
183
+ async function createPaymentLink(httpConfig, params) {
184
+ return request(httpConfig.config, "POST", "/v1/orders", {
185
+ body: params
186
+ });
187
+ }
188
+
189
+ // src/resources/paymentRoutes.ts
190
+ async function createPaymentRoute(httpConfig, params) {
191
+ return request(httpConfig.config, "POST", "/v1/payment-routes", {
192
+ body: params
193
+ });
194
+ }
195
+
196
+ // src/resources/payments.ts
197
+ async function getPayment(httpConfig, paymentId) {
198
+ return request(httpConfig.config, "GET", `/v1/merchants/payments/${encodeURIComponent(paymentId)}`);
199
+ }
200
+
201
+ // src/resources/balances.ts
202
+ async function listBalances(httpConfig, params) {
203
+ return request(httpConfig.config, "GET", "/v1/balances", {
204
+ params
205
+ });
206
+ }
207
+ async function getBalance(httpConfig, currencyId) {
208
+ return request(httpConfig.config, "GET", `/v1/balances/${encodeURIComponent(currencyId)}`);
209
+ }
210
+
211
+ // src/resources/quotes.ts
212
+ async function getQuote(httpConfig, params) {
213
+ return request(httpConfig.config, "POST", "/v1/quotes", {
214
+ body: params
215
+ });
216
+ }
217
+
218
+ // src/resources/payouts.ts
219
+ async function createPayout(httpConfig, params) {
220
+ return request(httpConfig.config, "POST", "/v1/payouts", {
221
+ body: params
222
+ });
223
+ }
224
+ async function listPayouts(httpConfig, params) {
225
+ return request(httpConfig.config, "GET", "/v1/payouts", {
226
+ params
227
+ });
228
+ }
229
+ async function getPayout(httpConfig, payoutId) {
230
+ return request(httpConfig.config, "GET", `/v1/payouts/${encodeURIComponent(payoutId)}`);
231
+ }
232
+
233
+ // src/resources/kyc.ts
234
+ async function getKYCStatus(httpConfig, customerId) {
235
+ return request(httpConfig.config, "GET", `/v1/kyc/${encodeURIComponent(customerId)}`);
236
+ }
237
+ async function submitKYC(httpConfig, params) {
238
+ return request(httpConfig.config, "POST", "/v1/kyc", {
239
+ body: params
240
+ });
241
+ }
242
+
243
+ // src/utils/webhooks.ts
244
+ async function verifyWebhookSignature(payload, signature, secret) {
245
+ try {
246
+ const encoder = new TextEncoder;
247
+ const keyData = encoder.encode(secret);
248
+ const key = await crypto.subtle.importKey("raw", keyData, { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
249
+ const payloadData = encoder.encode(payload);
250
+ const signatureBuffer = await crypto.subtle.sign("HMAC", key, payloadData);
251
+ const signatureArray = Array.from(new Uint8Array(signatureBuffer));
252
+ const expectedSignature = signatureArray.map((b) => b.toString(16).padStart(2, "0")).join("");
253
+ return constantTimeEqual(expectedSignature, signature);
254
+ } catch {
255
+ return false;
256
+ }
257
+ }
258
+ function constantTimeEqual(a, b) {
259
+ if (a.length !== b.length) {
260
+ return false;
261
+ }
262
+ let result = 0;
263
+ for (let i = 0;i < a.length; i++) {
264
+ result |= a.charCodeAt(i) ^ b.charCodeAt(i);
265
+ }
266
+ return result === 0;
267
+ }
268
+ function parseWebhookEvent(payload) {
269
+ try {
270
+ return JSON.parse(payload);
271
+ } catch (error) {
272
+ throw new Error(`Failed to parse webhook payload: ${error instanceof Error ? error.message : "Unknown error"}`);
273
+ }
274
+ }
275
+
276
+ // src/client/createClient.ts
277
+ var DEFAULT_CONFIG = {
278
+ environment: "production",
279
+ timeout: 30000,
280
+ retries: 3
281
+ };
282
+ var BASE_URL2 = "https://pay-api.swapped.com";
283
+ function createClient(config) {
284
+ const requiredConfig = {
285
+ ...DEFAULT_CONFIG,
286
+ ...config
287
+ };
288
+ const httpConfig = {
289
+ config: requiredConfig,
290
+ baseUrl: BASE_URL2
291
+ };
292
+ return {
293
+ orders: {
294
+ list: (params) => listOrders(httpConfig, params),
295
+ get: (orderId) => getOrder(httpConfig, orderId),
296
+ refund: (orderId, params) => refundOrder(httpConfig, orderId, params)
297
+ },
298
+ paymentLinks: {
299
+ create: (params) => createPaymentLink(httpConfig, params)
300
+ },
301
+ paymentRoutes: {
302
+ create: (params) => createPaymentRoute(httpConfig, params)
303
+ },
304
+ payments: {
305
+ get: (paymentId) => getPayment(httpConfig, paymentId)
306
+ },
307
+ balances: {
308
+ list: (params) => listBalances(httpConfig, params),
309
+ get: (currencyId) => getBalance(httpConfig, currencyId)
310
+ },
311
+ quotes: {
312
+ get: (params) => getQuote(httpConfig, params)
313
+ },
314
+ payouts: {
315
+ create: (params) => createPayout(httpConfig, params),
316
+ list: (params) => listPayouts(httpConfig, params),
317
+ get: (payoutId) => getPayout(httpConfig, payoutId)
318
+ },
319
+ kyc: {
320
+ getStatus: (customerId) => getKYCStatus(httpConfig, customerId),
321
+ submit: (params) => submitKYC(httpConfig, params)
322
+ },
323
+ verifyWebhookSignature,
324
+ parseWebhookEvent
325
+ };
326
+ }
327
+ export {
328
+ verifyWebhookSignature,
329
+ parseWebhookEvent,
330
+ createValidationError,
331
+ createRateLimitError,
332
+ createNotFoundError,
333
+ createClient,
334
+ createAuthenticationError,
335
+ SwappedValidationError,
336
+ SwappedRateLimitError,
337
+ SwappedNotFoundError,
338
+ SwappedError,
339
+ SwappedAuthenticationError
340
+ };
package/package.json CHANGED
@@ -1,20 +1,22 @@
1
1
  {
2
2
  "name": "swapped-commerce-sdk",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "TypeScript SDK for Swapped Commerce Integration API - Functional, performant, and fully typed",
5
5
  "type": "module",
6
- "main": "src/index.ts",
7
- "module": "src/index.ts",
8
- "types": "src/index.ts",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./src/index.ts",
9
9
  "exports": {
10
10
  ".": {
11
11
  "types": "./src/index.ts",
12
- "import": "./src/index.ts",
13
- "default": "./src/index.ts"
12
+ "import": "./dist/index.js",
13
+ "default": "./dist/index.js"
14
14
  }
15
15
  },
16
16
  "scripts": {
17
- "build": "bun build src/index.ts --outdir dist --target bun",
17
+ "build": "bun build src/index.ts --outdir dist --target node --format esm",
18
+ "build:dev": "bun build src/index.ts --outdir dist --target node --format esm",
19
+ "prepublishOnly": "bun run build",
18
20
  "test": "bun test",
19
21
  "test:watch": "bun test --watch",
20
22
  "test:coverage": "bun test --coverage",
@@ -50,6 +52,7 @@
50
52
  "typescript": "^5"
51
53
  },
52
54
  "files": [
55
+ "dist",
53
56
  "src",
54
57
  "README.md",
55
58
  "LICENSE"
@@ -17,7 +17,7 @@ export async function listBalances(
17
17
  return request<BalancesResponse>(
18
18
  httpConfig.config,
19
19
  'GET',
20
- '/v1/merchants/balances',
20
+ '/v1/balances',
21
21
  {
22
22
  params,
23
23
  }
@@ -34,6 +34,6 @@ export async function getBalance(
34
34
  return request<Balance>(
35
35
  httpConfig.config,
36
36
  'GET',
37
- `/v1/merchants/balances/${encodeURIComponent(currencyId)}`
37
+ `/v1/balances/${encodeURIComponent(currencyId)}`
38
38
  )
39
39
  }
@@ -17,7 +17,7 @@ export async function getKYCStatus(
17
17
  return request<KYCStatusResponse>(
18
18
  httpConfig.config,
19
19
  'GET',
20
- `/v1/merchants/kyc/${encodeURIComponent(customerId)}`
20
+ `/v1/kyc/${encodeURIComponent(customerId)}`
21
21
  )
22
22
  }
23
23
 
@@ -31,7 +31,7 @@ export async function submitKYC(
31
31
  return request<SubmitKYCResponse>(
32
32
  httpConfig.config,
33
33
  'POST',
34
- '/v1/merchants/kyc',
34
+ '/v1/kyc',
35
35
  {
36
36
  body: params,
37
37
  }
@@ -16,7 +16,7 @@ export async function listOrders(
16
16
  httpConfig: HttpConfig,
17
17
  params?: Readonly<ListOrdersParams>
18
18
  ): Promise<ApiResponse<OrdersResponse>> {
19
- return request<OrdersResponse>(httpConfig.config, 'GET', '/v1/merchants/orders', {
19
+ return request<OrdersResponse>(httpConfig.config, 'GET', '/v1/orders', {
20
20
  params,
21
21
  })
22
22
  }
@@ -31,7 +31,7 @@ export async function getOrder(
31
31
  return request<Order>(
32
32
  httpConfig.config,
33
33
  'GET',
34
- `/v1/merchants/orders/${encodeURIComponent(orderId)}`
34
+ `/v1/orders/${encodeURIComponent(orderId)}`
35
35
  )
36
36
  }
37
37
 
@@ -16,7 +16,7 @@ export async function createPaymentRoute(
16
16
  return request<PaymentRouteResponse>(
17
17
  httpConfig.config,
18
18
  'POST',
19
- '/v1/merchants/payment-routes',
19
+ '/v1/payment-routes',
20
20
  {
21
21
  body: params,
22
22
  }
@@ -19,7 +19,7 @@ export async function createPayout(
19
19
  return request<CreatePayoutResponse>(
20
20
  httpConfig.config,
21
21
  'POST',
22
- '/v1/merchants/payouts',
22
+ '/v1/payouts',
23
23
  {
24
24
  body: params,
25
25
  }
@@ -36,7 +36,7 @@ export async function listPayouts(
36
36
  return request<PayoutsResponse>(
37
37
  httpConfig.config,
38
38
  'GET',
39
- '/v1/merchants/payouts',
39
+ '/v1/payouts',
40
40
  {
41
41
  params,
42
42
  }
@@ -53,6 +53,6 @@ export async function getPayout(
53
53
  return request<Payout>(
54
54
  httpConfig.config,
55
55
  'GET',
56
- `/v1/merchants/payouts/${encodeURIComponent(payoutId)}`
56
+ `/v1/payouts/${encodeURIComponent(payoutId)}`
57
57
  )
58
58
  }
@@ -16,7 +16,7 @@ export async function getQuote(
16
16
  return request<QuoteResponse>(
17
17
  httpConfig.config,
18
18
  'POST',
19
- '/v1/merchants/quotes',
19
+ '/v1/quotes',
20
20
  {
21
21
  body: params,
22
22
  }