telebirr-nodejs 1.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.
@@ -0,0 +1,104 @@
1
+ type TelebirrMode = "simulate" | "sandbox" | "production";
2
+ type IntegrationOption = "C2B" | "B2B";
3
+ interface TelebirrConfig {
4
+ appId: string;
5
+ appSecret: string;
6
+ merchantAppId: string;
7
+ merchantCode: string;
8
+ privateKey: string;
9
+ notifyUrl: string;
10
+ redirectUrl: string;
11
+ mode: TelebirrMode;
12
+ http: boolean;
13
+ integrationOption: IntegrationOption;
14
+ }
15
+
16
+ interface GenerateCheckoutUrlInput {
17
+ title: string;
18
+ amount: string;
19
+ merchOrderId?: string;
20
+ callbackInfo?: string;
21
+ }
22
+
23
+ type TelebirrTradeStatus = "PAY_SUCCESS" | "PAY_FAILED" | "WAIT_PAY" | "ORDER_CLOSED" | "PAYING" | "ACCEPTED" | "REFUNDING" | "REFUND_SUCCESS" | "REFUND_FAILED";
24
+ interface QueryOrderResponse {
25
+ result: "SUCCESS" | "FAIL";
26
+ code: string;
27
+ msg: string;
28
+ sign: string;
29
+ sign_type: "SHA256WithRSA";
30
+ nonce_str: string;
31
+ biz_content: {
32
+ merch_order_id: string;
33
+ order_status: TelebirrTradeStatus;
34
+ payment_order_id: string;
35
+ trans_time: string;
36
+ trans_currency: "ETB";
37
+ total_amount: string;
38
+ trans_id: string;
39
+ };
40
+ }
41
+
42
+ interface RefundInput {
43
+ merchOrderId: string;
44
+ refundRequestNo: string;
45
+ amount: string;
46
+ refundReason?: string;
47
+ }
48
+ type TelebirrRefundStatus = "REFUND_SUCCESS" | "REFUNDING" | "REFUND_FAILED" | "REFUND_DUPLICATED";
49
+ interface RefundResponse {
50
+ result: "SUCCESS" | "FAIL";
51
+ code: string;
52
+ msg: string;
53
+ sign: string;
54
+ sign_type: "SHA256WithRSA";
55
+ nonce_str: string;
56
+ biz_content: {
57
+ /** Short code registered by a merchant with Mobile Money */
58
+ merch_code: string;
59
+ /** Order ID on the merchant side */
60
+ merch_order_id: string;
61
+ /** Original transaction order ID on the payment side */
62
+ trans_order_id: string;
63
+ /** Refund transaction order ID on the payment side */
64
+ refund_order_id: string;
65
+ /** Refund amount */
66
+ refund_amount: string;
67
+ /** Refund currency (e.g. ETB) */
68
+ refund_currency: string;
69
+ /** Refund status */
70
+ refund_status: TelebirrRefundStatus;
71
+ /**
72
+ * Refund success timestamp.
73
+ * Only present when refund_status === "REFUND_SUCCESS"
74
+ */
75
+ refund_time?: string;
76
+ };
77
+ }
78
+
79
+ declare class TelebirrClient {
80
+ private token?;
81
+ private config;
82
+ constructor(config: TelebirrConfig);
83
+ getFabricToken(): Promise<any>;
84
+ private createCheckoutUrl;
85
+ preOrder(input: GenerateCheckoutUrlInput): Promise<string | void>;
86
+ queryOrder(input: string): Promise<QueryOrderResponse | void>;
87
+ refundOrder(input: RefundInput): Promise<RefundResponse | void>;
88
+ private static readonly TOKEN_EXPIRY_SAFETY_WINDOW_MS;
89
+ private isTokenExpired;
90
+ private parseTelebirrDate;
91
+ }
92
+
93
+ interface KeyPairOptions {
94
+ dir?: string;
95
+ privateKeyName?: string;
96
+ publicKeyName?: string;
97
+ overwrite?: boolean;
98
+ }
99
+ declare function generateKeys(options?: KeyPairOptions): {
100
+ privateKeyPath: string;
101
+ publicKeyPath: string;
102
+ };
103
+
104
+ export { TelebirrClient, type TelebirrConfig, generateKeys };
@@ -0,0 +1,104 @@
1
+ type TelebirrMode = "simulate" | "sandbox" | "production";
2
+ type IntegrationOption = "C2B" | "B2B";
3
+ interface TelebirrConfig {
4
+ appId: string;
5
+ appSecret: string;
6
+ merchantAppId: string;
7
+ merchantCode: string;
8
+ privateKey: string;
9
+ notifyUrl: string;
10
+ redirectUrl: string;
11
+ mode: TelebirrMode;
12
+ http: boolean;
13
+ integrationOption: IntegrationOption;
14
+ }
15
+
16
+ interface GenerateCheckoutUrlInput {
17
+ title: string;
18
+ amount: string;
19
+ merchOrderId?: string;
20
+ callbackInfo?: string;
21
+ }
22
+
23
+ type TelebirrTradeStatus = "PAY_SUCCESS" | "PAY_FAILED" | "WAIT_PAY" | "ORDER_CLOSED" | "PAYING" | "ACCEPTED" | "REFUNDING" | "REFUND_SUCCESS" | "REFUND_FAILED";
24
+ interface QueryOrderResponse {
25
+ result: "SUCCESS" | "FAIL";
26
+ code: string;
27
+ msg: string;
28
+ sign: string;
29
+ sign_type: "SHA256WithRSA";
30
+ nonce_str: string;
31
+ biz_content: {
32
+ merch_order_id: string;
33
+ order_status: TelebirrTradeStatus;
34
+ payment_order_id: string;
35
+ trans_time: string;
36
+ trans_currency: "ETB";
37
+ total_amount: string;
38
+ trans_id: string;
39
+ };
40
+ }
41
+
42
+ interface RefundInput {
43
+ merchOrderId: string;
44
+ refundRequestNo: string;
45
+ amount: string;
46
+ refundReason?: string;
47
+ }
48
+ type TelebirrRefundStatus = "REFUND_SUCCESS" | "REFUNDING" | "REFUND_FAILED" | "REFUND_DUPLICATED";
49
+ interface RefundResponse {
50
+ result: "SUCCESS" | "FAIL";
51
+ code: string;
52
+ msg: string;
53
+ sign: string;
54
+ sign_type: "SHA256WithRSA";
55
+ nonce_str: string;
56
+ biz_content: {
57
+ /** Short code registered by a merchant with Mobile Money */
58
+ merch_code: string;
59
+ /** Order ID on the merchant side */
60
+ merch_order_id: string;
61
+ /** Original transaction order ID on the payment side */
62
+ trans_order_id: string;
63
+ /** Refund transaction order ID on the payment side */
64
+ refund_order_id: string;
65
+ /** Refund amount */
66
+ refund_amount: string;
67
+ /** Refund currency (e.g. ETB) */
68
+ refund_currency: string;
69
+ /** Refund status */
70
+ refund_status: TelebirrRefundStatus;
71
+ /**
72
+ * Refund success timestamp.
73
+ * Only present when refund_status === "REFUND_SUCCESS"
74
+ */
75
+ refund_time?: string;
76
+ };
77
+ }
78
+
79
+ declare class TelebirrClient {
80
+ private token?;
81
+ private config;
82
+ constructor(config: TelebirrConfig);
83
+ getFabricToken(): Promise<any>;
84
+ private createCheckoutUrl;
85
+ preOrder(input: GenerateCheckoutUrlInput): Promise<string | void>;
86
+ queryOrder(input: string): Promise<QueryOrderResponse | void>;
87
+ refundOrder(input: RefundInput): Promise<RefundResponse | void>;
88
+ private static readonly TOKEN_EXPIRY_SAFETY_WINDOW_MS;
89
+ private isTokenExpired;
90
+ private parseTelebirrDate;
91
+ }
92
+
93
+ interface KeyPairOptions {
94
+ dir?: string;
95
+ privateKeyName?: string;
96
+ publicKeyName?: string;
97
+ overwrite?: boolean;
98
+ }
99
+ declare function generateKeys(options?: KeyPairOptions): {
100
+ privateKeyPath: string;
101
+ publicKeyPath: string;
102
+ };
103
+
104
+ export { TelebirrClient, type TelebirrConfig, generateKeys };
package/dist/index.js ADDED
@@ -0,0 +1,489 @@
1
+ // src/utils/credentials.ts
2
+ import fs2 from "fs";
3
+ import { randomUUID, randomBytes } from "crypto";
4
+ import { customAlphabet } from "nanoid";
5
+
6
+ // src/utils/keys.ts
7
+ import { generateKeyPairSync } from "crypto";
8
+ import fs from "fs";
9
+ import path from "path";
10
+ function generateKeys(options = {}) {
11
+ const {
12
+ dir = process.cwd(),
13
+ privateKeyName = "telebirr_private.pem",
14
+ publicKeyName = "telebirr_public.pem",
15
+ overwrite = false
16
+ } = options;
17
+ const privateKeyPath = path.join(dir, privateKeyName);
18
+ const publicKeyPath = path.join(dir, publicKeyName);
19
+ const exists = fs.existsSync(privateKeyPath) && fs.existsSync(publicKeyPath);
20
+ if (exists && !overwrite) {
21
+ return { privateKeyPath, publicKeyPath };
22
+ }
23
+ const { privateKey, publicKey } = generateKeyPairSync("rsa", {
24
+ modulusLength: 2048,
25
+ publicKeyEncoding: {
26
+ type: "pkcs1",
27
+ format: "pem"
28
+ },
29
+ privateKeyEncoding: {
30
+ type: "pkcs1",
31
+ format: "pem"
32
+ }
33
+ });
34
+ fs.writeFileSync(privateKeyPath, privateKey, { mode: 384 });
35
+ fs.writeFileSync(publicKeyPath, publicKey);
36
+ return { privateKeyPath, publicKeyPath };
37
+ }
38
+
39
+ // src/utils/credentials.ts
40
+ var numeric16 = customAlphabet("0123456789", 16);
41
+ var numeric6 = customAlphabet("0123456789", 6);
42
+ function generateCredentials() {
43
+ const { privateKeyPath } = generateKeys();
44
+ const merchantPrivateKey = fs2.readFileSync(privateKeyPath, "utf8");
45
+ return {
46
+ fabricAppId: randomUUID(),
47
+ fabricAppSecret: randomBytes(16).toString("hex"),
48
+ merchantAppId: numeric16(),
49
+ merchantCode: numeric6(),
50
+ merchantPrivateKey
51
+ };
52
+ }
53
+
54
+ // src/services/requestToken.ts
55
+ import http from "http";
56
+ import https from "https";
57
+
58
+ // src/constants/urls.ts
59
+ var TELEBIRR_URLS = {
60
+ sandbox: {
61
+ apiBase: "https://developerportal.ethiotelebirr.et:38443/apiaccess/payment/gateway",
62
+ webBase: "https://developerportal.ethiotelebirr.et:38443/payment/web/paygate?"
63
+ },
64
+ production: {
65
+ apiBase: "https://telebirrappcube.ethiomobilemoney.et:38443/apiaccess/payment/gateway",
66
+ webBase: "https://telebirrappcube.ethiomobilemoney.et:38443/payment/web/paygate?"
67
+ },
68
+ simulate: {
69
+ apiBase: "http://localhost:3000",
70
+ webBase: "http://localhost:3000/web/?"
71
+ }
72
+ // simulate: {
73
+ // apiBase: "https://telebirr-node-simulator.onrender.com",
74
+ // webBase: "https://telebirr-node-simulator.onrender.com/web/?",
75
+ // },
76
+ };
77
+ var CHECKOUT_OTHER_PARAMS = "&version=1.0&trade_type=Checkout";
78
+
79
+ // src/services/requestToken.ts
80
+ function requestToken(config) {
81
+ const isHttps = TELEBIRR_URLS[config.mode].apiBase.startsWith("https://");
82
+ const client = isHttps ? https : http;
83
+ return new Promise((resolve, reject) => {
84
+ const req = client.request(
85
+ ` ${TELEBIRR_URLS[config.mode].apiBase}/payment/v1/token`,
86
+ {
87
+ method: "POST",
88
+ headers: {
89
+ "Content-Type": "application/json",
90
+ "X-APP-Key": config.appId
91
+ },
92
+ ...isHttps && { rejectUnauthorized: false }
93
+ },
94
+ (res) => {
95
+ let body = "";
96
+ res.on("data", (chunk) => body += chunk);
97
+ res.on("end", () => resolve(body));
98
+ }
99
+ );
100
+ req.on("error", reject);
101
+ req.write(JSON.stringify({ appSecret: config.appSecret }));
102
+ req.end();
103
+ });
104
+ }
105
+
106
+ // src/services/requestCreateOrder.ts
107
+ import http2 from "http";
108
+ import https2 from "https";
109
+
110
+ // src/utils/nonce.ts
111
+ import { randomBytes as randomBytes2 } from "crypto";
112
+ function createNonceStr() {
113
+ const bytes = Math.ceil(16);
114
+ return randomBytes2(bytes).toString("hex").slice(0, 32);
115
+ }
116
+
117
+ // src/utils/timestamp.ts
118
+ function createTimestamp() {
119
+ return Math.floor(Date.now() / 1e3).toString();
120
+ }
121
+
122
+ // src/utils/signature.ts
123
+ import crypto from "crypto";
124
+ function flattenParams(params) {
125
+ const flat = {};
126
+ for (const key in params) {
127
+ const value = params[key];
128
+ if (value === void 0 || value === null || value === "" || key === "sign" || key === "signType" || key === "sign_type") {
129
+ continue;
130
+ }
131
+ if (key === "biz_content" && typeof value === "object") {
132
+ for (const bizKey in value) {
133
+ const bizValue = value[bizKey];
134
+ if (bizValue !== void 0 && bizValue !== null && bizValue !== "") {
135
+ flat[bizKey] = String(bizValue);
136
+ }
137
+ }
138
+ } else {
139
+ flat[key] = String(value);
140
+ }
141
+ }
142
+ return flat;
143
+ }
144
+ function buildSignString(params) {
145
+ const flat = flattenParams(params);
146
+ return Object.keys(flat).sort().map((key) => `${key}=${flat[key]}`).join("&");
147
+ }
148
+ function signRequest(data, privateKey) {
149
+ const signString = buildSignString(data);
150
+ return crypto.createSign("RSA-SHA256").update(signString, "utf8").sign(privateKey, "base64");
151
+ }
152
+
153
+ // src/services/requestCreateOrder.ts
154
+ function requestCreateOrder(fabricToken, input, config) {
155
+ const reqBody = {
156
+ timestamp: createTimestamp(),
157
+ nonce_str: createNonceStr(),
158
+ method: "payment.preorder",
159
+ version: "1.0",
160
+ biz_content: {
161
+ appid: config.merchantAppId,
162
+ merch_code: config.merchantCode,
163
+ merch_order_id: input.merchOrderId,
164
+ notify_url: config.notifyUrl,
165
+ redirect_url: config.redirectUrl,
166
+ trade_type: "Checkout",
167
+ title: input.title,
168
+ total_amount: input.amount,
169
+ trans_currency: "ETB",
170
+ timeout_express: "120m",
171
+ business_type: "BuyGoods",
172
+ payee_type: "3000",
173
+ payee_identifier: config.merchantCode,
174
+ payee_identifier_type: "04",
175
+ callback_info: "From web"
176
+ }
177
+ };
178
+ reqBody.sign = signRequest(reqBody, config.privateKey);
179
+ reqBody.sign_type = "SHA256WithRSA";
180
+ const payload = JSON.stringify(reqBody);
181
+ const baseUrl = TELEBIRR_URLS[config.mode].apiBase;
182
+ const isHttps = baseUrl.startsWith("https://");
183
+ const client = isHttps ? https2 : http2;
184
+ return new Promise((resolve, reject) => {
185
+ const req = client.request(
186
+ `${baseUrl}/payment/v1/merchant/preOrder`,
187
+ {
188
+ method: "POST",
189
+ headers: {
190
+ "Content-Type": "application/json",
191
+ "Content-Length": Buffer.byteLength(payload),
192
+ "X-APP-Key": config.appId,
193
+ Authorization: fabricToken
194
+ },
195
+ ...isHttps && { rejectUnauthorized: false }
196
+ },
197
+ (res) => {
198
+ let raw = "";
199
+ res.on("data", (chunk) => {
200
+ raw += chunk;
201
+ });
202
+ res.on("end", () => {
203
+ const status = res.statusCode || 0;
204
+ let parsed = raw;
205
+ try {
206
+ parsed = JSON.parse(raw);
207
+ } catch {
208
+ }
209
+ if (status < 200 || status >= 300) {
210
+ return reject({
211
+ message: "Telebirr preorder request failed",
212
+ status,
213
+ data: parsed,
214
+ headers: res.headers
215
+ });
216
+ }
217
+ resolve({
218
+ data: parsed,
219
+ status,
220
+ headers: res.headers
221
+ });
222
+ });
223
+ }
224
+ );
225
+ req.on("error", (err) => {
226
+ reject({
227
+ message: "Telebirr preorder network error",
228
+ cause: err,
229
+ code: err.code
230
+ });
231
+ });
232
+ req.write(payload);
233
+ req.end();
234
+ });
235
+ }
236
+
237
+ // src/services/requestRefundOrder.ts
238
+ import http3 from "http";
239
+ import https3 from "https";
240
+ function requestRefund(fabricToken, input, config) {
241
+ const reqBody = {
242
+ timestamp: createTimestamp(),
243
+ nonce_str: createNonceStr(),
244
+ method: "payment.refund",
245
+ version: "1.0",
246
+ biz_content: {
247
+ appid: config.merchantAppId,
248
+ merch_code: config.merchantCode,
249
+ merch_order_id: input.merchOrderId,
250
+ trans_currency: "ETB",
251
+ actual_amount: input.amount,
252
+ refund_request_no: input.refundRequestNo,
253
+ refund_reason: input.refundReason
254
+ }
255
+ };
256
+ reqBody.sign = signRequest(reqBody, config.privateKey);
257
+ reqBody.sign_type = "SHA256WithRSA";
258
+ const payload = JSON.stringify(reqBody);
259
+ const baseUrl = TELEBIRR_URLS[config.mode].apiBase;
260
+ const isHttps = baseUrl.startsWith("https://");
261
+ const client = isHttps ? https3 : http3;
262
+ return new Promise((resolve, reject) => {
263
+ const req = client.request(
264
+ `${baseUrl}/payment/v1/merchant/refund`,
265
+ {
266
+ method: "POST",
267
+ headers: {
268
+ "Content-Type": "application/json",
269
+ "Content-Length": Buffer.byteLength(payload),
270
+ "X-APP-Key": config.appId,
271
+ Authorization: fabricToken
272
+ },
273
+ ...isHttps && { rejectUnauthorized: false }
274
+ },
275
+ (res) => {
276
+ let raw = "";
277
+ res.on("data", (chunk) => {
278
+ raw += chunk;
279
+ });
280
+ res.on("end", () => {
281
+ const status = res.statusCode || 0;
282
+ let parsed = raw;
283
+ try {
284
+ parsed = JSON.parse(raw);
285
+ } catch {
286
+ }
287
+ if (status < 200 || status >= 300) {
288
+ return reject({
289
+ message: "Telebirr refund request failed",
290
+ status,
291
+ data: parsed,
292
+ headers: res.headers
293
+ });
294
+ }
295
+ resolve({
296
+ data: parsed,
297
+ status,
298
+ headers: res.headers
299
+ });
300
+ });
301
+ }
302
+ );
303
+ req.on("error", (err) => {
304
+ reject({
305
+ message: "Telebirr refund network error",
306
+ cause: err,
307
+ code: err.code
308
+ });
309
+ });
310
+ req.write(payload);
311
+ req.end();
312
+ });
313
+ }
314
+
315
+ // src/services/requestQueryOrder.ts
316
+ import http4 from "http";
317
+ import https4 from "https";
318
+ function requestQueryOrder(fabricToken, merchOrderId, config) {
319
+ const reqBody = {
320
+ timestamp: createTimestamp(),
321
+ nonce_str: createNonceStr(),
322
+ method: "payment.queryorder",
323
+ version: "1.0",
324
+ biz_content: {
325
+ appid: config.merchantAppId,
326
+ merch_code: config.merchantCode,
327
+ merch_order_id: merchOrderId
328
+ }
329
+ };
330
+ reqBody.sign = signRequest(reqBody, config.privateKey);
331
+ reqBody.sign_type = "SHA256WithRSA";
332
+ const payload = JSON.stringify(reqBody);
333
+ const baseUrl = TELEBIRR_URLS[config.mode].apiBase;
334
+ const isHttps = baseUrl.startsWith("https://");
335
+ const client = isHttps ? https4 : http4;
336
+ return new Promise((resolve, reject) => {
337
+ const req = client.request(
338
+ `${baseUrl}/payment/v1/merchant/queryOrder`,
339
+ {
340
+ method: "POST",
341
+ headers: {
342
+ "Content-Type": "application/json",
343
+ "Content-Length": Buffer.byteLength(payload),
344
+ "X-APP-Key": config.appId,
345
+ Authorization: fabricToken
346
+ },
347
+ ...isHttps && { rejectUnauthorized: false }
348
+ },
349
+ (res) => {
350
+ let raw = "";
351
+ res.on("data", (chunk) => {
352
+ raw += chunk;
353
+ });
354
+ res.on("end", () => {
355
+ const status = res.statusCode || 0;
356
+ let parsed = raw;
357
+ try {
358
+ parsed = JSON.parse(raw);
359
+ } catch {
360
+ }
361
+ if (status < 200 || status >= 300) {
362
+ return reject({
363
+ message: "Telebirr queryOrder request failed",
364
+ status,
365
+ data: parsed,
366
+ headers: res.headers
367
+ });
368
+ }
369
+ resolve({
370
+ data: parsed,
371
+ status,
372
+ headers: res.headers
373
+ });
374
+ });
375
+ }
376
+ );
377
+ req.on("error", (err) => {
378
+ reject({
379
+ message: "Telebirr queryOrder network error",
380
+ cause: err,
381
+ code: err.code
382
+ });
383
+ });
384
+ req.write(payload);
385
+ req.end();
386
+ });
387
+ }
388
+
389
+ // src/client.ts
390
+ var TelebirrClient = class _TelebirrClient {
391
+ token;
392
+ config;
393
+ constructor(config) {
394
+ if (config.mode === "simulate") {
395
+ const creds = generateCredentials();
396
+ this.config = {
397
+ ...config,
398
+ appId: config.appId ?? creds.fabricAppId,
399
+ appSecret: config.appSecret ?? creds.fabricAppSecret,
400
+ merchantAppId: config.merchantAppId ?? creds.merchantAppId,
401
+ merchantCode: config.merchantCode ?? creds.merchantCode,
402
+ privateKey: creds.merchantPrivateKey
403
+ };
404
+ } else {
405
+ this.config = config;
406
+ }
407
+ }
408
+ async getFabricToken() {
409
+ if (this.token && !this.isTokenExpired(this.token)) {
410
+ return this.token;
411
+ }
412
+ let token = await requestToken(this.config);
413
+ token = JSON.parse(token);
414
+ if (!token) return;
415
+ this.token = token;
416
+ return token;
417
+ }
418
+ createCheckoutUrl(prepayId) {
419
+ const map = {
420
+ appid: this.config.merchantAppId,
421
+ merch_code: this.config.merchantCode,
422
+ nonce_str: createNonceStr(),
423
+ prepay_id: prepayId,
424
+ timestamp: createTimestamp()
425
+ };
426
+ const sign = signRequest(map, this.config.privateKey);
427
+ const rawRequest = [
428
+ `appid=${map.appid}`,
429
+ `merch_code=${map.merch_code}`,
430
+ `nonce_str=${map.nonce_str}`,
431
+ `prepay_id=${map.prepay_id}`,
432
+ `timestamp=${map.timestamp}`,
433
+ `sign=${sign}`,
434
+ `sign_type=SHA256WithRSA`
435
+ ].join("&");
436
+ const webBase = TELEBIRR_URLS[this.config.mode].webBase;
437
+ return webBase + rawRequest + CHECKOUT_OTHER_PARAMS;
438
+ }
439
+ async preOrder(input) {
440
+ const token = await this.getFabricToken();
441
+ if (!token) return;
442
+ let response = await requestCreateOrder(
443
+ token.token,
444
+ input,
445
+ this.config
446
+ );
447
+ if (!response) return;
448
+ return this.createCheckoutUrl(response.data.biz_content.prepay_id);
449
+ }
450
+ async queryOrder(input) {
451
+ let token = await this.getFabricToken();
452
+ if (!token) return;
453
+ const response = await requestQueryOrder(
454
+ token.token,
455
+ input,
456
+ this.config
457
+ );
458
+ return response.data;
459
+ }
460
+ async refundOrder(input) {
461
+ const token = await this.getFabricToken();
462
+ if (!token) return;
463
+ const response = await requestRefund(token.token, input, this.config);
464
+ return response.data;
465
+ }
466
+ static TOKEN_EXPIRY_SAFETY_WINDOW_MS = 5 * 60 * 1e3;
467
+ isTokenExpired(token) {
468
+ if (!token) {
469
+ return true;
470
+ }
471
+ const now = Date.now();
472
+ const expiry = this.parseTelebirrDate(token.expirationDate).getTime();
473
+ return now >= expiry - _TelebirrClient.TOKEN_EXPIRY_SAFETY_WINDOW_MS;
474
+ }
475
+ parseTelebirrDate(value) {
476
+ const year = Number(value.slice(0, 4));
477
+ const month = Number(value.slice(4, 6)) - 1;
478
+ const day = Number(value.slice(6, 8));
479
+ const hour = Number(value.slice(8, 10));
480
+ const minute = Number(value.slice(10, 12));
481
+ const second = Number(value.slice(12, 14));
482
+ return new Date(Date.UTC(year, month, day, hour, minute, second));
483
+ }
484
+ };
485
+ export {
486
+ TelebirrClient,
487
+ generateKeys
488
+ };
489
+ //# sourceMappingURL=index.js.map