telebirr-nodejs 1.0.8 → 1.1.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.
- package/LICENSE +21 -0
- package/README.md +19 -11
- package/dist/index.cjs +43 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -4
- package/dist/index.d.ts +2 -4
- package/dist/index.js +42 -21
- package/dist/index.js.map +1 -1
- package/package.json +17 -5
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) [2026] [Chernet Manaye]
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -45,9 +45,9 @@ You should never hard-code secrets. Always load them from process.env.
|
|
|
45
45
|
---
|
|
46
46
|
|
|
47
47
|
```bash
|
|
48
|
-
import {
|
|
48
|
+
import { C2B } from "telebirr-nodejs";
|
|
49
49
|
|
|
50
|
-
const
|
|
50
|
+
const c2bClient = new C2B({
|
|
51
51
|
mode: "sandbox", // "simulate" | "sandbox" | "production"
|
|
52
52
|
appId: process.env.FABRIC_APP_ID!,
|
|
53
53
|
appSecret: process.env.FABRIC_APP_SECRET!,
|
|
@@ -57,7 +57,6 @@ const client = new TelebirrClient({
|
|
|
57
57
|
notifyUrl: process.env.TELEBIRR_NOTIFY_URL!,
|
|
58
58
|
redirectUrl: process.env.TELEBIRR_REDIRECT_URL!,
|
|
59
59
|
http: true, // allow HTTP in simulator mode
|
|
60
|
-
IntegrationOption: "C2B",
|
|
61
60
|
});
|
|
62
61
|
```
|
|
63
62
|
|
|
@@ -89,7 +88,7 @@ Creates an order and redirects the user to the Telebirr checkout page.
|
|
|
89
88
|
|
|
90
89
|
```bash
|
|
91
90
|
app.post("/payment/initiate", async (req, res) => {
|
|
92
|
-
const checkoutUrl = await
|
|
91
|
+
const checkoutUrl = await c2bClient.preOrder({
|
|
93
92
|
merchOrderId: "order123",
|
|
94
93
|
title: "Phone",
|
|
95
94
|
amount: "12",
|
|
@@ -112,7 +111,7 @@ Used to check the payment result using the merchant order ID.
|
|
|
112
111
|
app.get("/payment/status/:merchOrderId", async (req, res) => {
|
|
113
112
|
const { merchOrderId } = req.body;
|
|
114
113
|
|
|
115
|
-
const info = await
|
|
114
|
+
const info = await c2bClient.queryOrder(merchOrderId);
|
|
116
115
|
|
|
117
116
|
res.json(info);
|
|
118
117
|
});
|
|
@@ -129,7 +128,7 @@ Refunds a completed transaction.
|
|
|
129
128
|
|
|
130
129
|
```bash
|
|
131
130
|
app.post("/payment/refund", async (req, res) => {
|
|
132
|
-
const refundData = await
|
|
131
|
+
const refundData = await c2bClient.refundOrder({
|
|
133
132
|
merchOrderId: "order123",
|
|
134
133
|
refundRequestNo: "original-transaction-id",
|
|
135
134
|
refundReason: "customer request",
|
|
@@ -151,19 +150,24 @@ https://developer.ethiotelecom.et/docs/H5%20C2B%20Web%20Payment%20Integration%20
|
|
|
151
150
|
To use the simulator provided by this package, set the mode to simulate.
|
|
152
151
|
|
|
153
152
|
```bash
|
|
154
|
-
import {
|
|
153
|
+
import { C2B } from "telebirr-nodejs";
|
|
155
154
|
|
|
156
|
-
const
|
|
155
|
+
const c2bClient = new C2B({
|
|
157
156
|
mode: "simulate",
|
|
157
|
+
appId: process.env.FABRIC_APP_ID!,
|
|
158
|
+
appSecret: process.env.FABRIC_APP_SECRET!,
|
|
159
|
+
merchantAppId: process.env.MERCHANT_APP_ID!,
|
|
160
|
+
merchantCode: process.env.MERCHANT_CODE!,
|
|
161
|
+
merchantPrivateKey: process.env.MERCHANT_PRIVATE_KEY!,
|
|
158
162
|
notifyUrl: "https://example.com/notify",
|
|
159
163
|
redirectUrl: "https://example.com/redirect",
|
|
160
|
-
http: true
|
|
161
|
-
IntegrationOption: "C2B",
|
|
164
|
+
http: true
|
|
162
165
|
});
|
|
163
166
|
|
|
164
167
|
```
|
|
165
168
|
|
|
166
|
-
This
|
|
169
|
+
This mode will generate credentials and add the in .env file in your project root directory
|
|
170
|
+
The simulator is for learning and development purposes only.
|
|
167
171
|
The simulation server is provided by this package, not by Telebirr. For real testing, use Telebirr’s sandbox mode and whitelist your public IP address in the Telebirr portal.
|
|
168
172
|
|
|
169
173
|
---
|
|
@@ -203,3 +207,7 @@ generateKeys({
|
|
|
203
207
|
This will generate two .pem files in your root directory.
|
|
204
208
|
|
|
205
209
|
The merchantPrivateKey option always accepts a string, so you must read the private key file using Node.js fs and pass the value to the client configuration.
|
|
210
|
+
|
|
211
|
+
## License
|
|
212
|
+
|
|
213
|
+
MIT © Chernet Manaye
|
package/dist/index.cjs
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } var _class;// src/utils/credentials.ts
|
|
2
2
|
var _fs = require('fs'); var _fs2 = _interopRequireDefault(_fs);
|
|
3
|
+
var _path = require('path'); var _path2 = _interopRequireDefault(_path);
|
|
3
4
|
var _crypto = require('crypto'); var _crypto2 = _interopRequireDefault(_crypto);
|
|
4
5
|
var _nanoid = require('nanoid');
|
|
5
6
|
|
|
6
7
|
// src/utils/keys.ts
|
|
7
8
|
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
|
|
10
11
|
function generateKeys(options = {}) {
|
|
11
12
|
const {
|
|
12
13
|
dir = process.cwd(),
|
|
@@ -39,16 +40,43 @@ function generateKeys(options = {}) {
|
|
|
39
40
|
// src/utils/credentials.ts
|
|
40
41
|
var numeric16 = _nanoid.customAlphabet.call(void 0, "0123456789", 16);
|
|
41
42
|
var numeric6 = _nanoid.customAlphabet.call(void 0, "0123456789", 6);
|
|
43
|
+
var ENV_FILE_NAME = ".env";
|
|
42
44
|
function generateCredentials() {
|
|
43
|
-
const
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
45
|
+
const envPath = _path2.default.join(process.cwd(), ENV_FILE_NAME);
|
|
46
|
+
const existingEnv = _fs2.default.existsSync(envPath) ? _fs2.default.readFileSync(envPath, "utf8") : "";
|
|
47
|
+
const existingKeys = new Set(
|
|
48
|
+
existingEnv.split("\n").map((line) => line.split("=")[0].trim()).filter(Boolean)
|
|
49
|
+
);
|
|
50
|
+
const entries = [];
|
|
51
|
+
const addIfMissing = (key, value) => {
|
|
52
|
+
if (!existingKeys.has(key)) {
|
|
53
|
+
entries.push(`${key}=${value}`);
|
|
54
|
+
}
|
|
51
55
|
};
|
|
56
|
+
let merchantPrivateKey = "";
|
|
57
|
+
if (!existingKeys.has("MERCHANT_PRIVATE_KEY")) {
|
|
58
|
+
const { privateKeyPath } = generateKeys();
|
|
59
|
+
merchantPrivateKey = _fs2.default.readFileSync(privateKeyPath, "utf8").replace(/\n/g, "\\n");
|
|
60
|
+
}
|
|
61
|
+
addIfMissing("FABRIC_APP_ID", _nullishCoalesce(process.env.FABRIC_APP_ID, () => ( _crypto.randomUUID.call(void 0, ))));
|
|
62
|
+
addIfMissing(
|
|
63
|
+
"FABRIC_APP_SECRET",
|
|
64
|
+
_nullishCoalesce(process.env.FABRIC_APP_SECRET, () => ( _crypto.randomBytes.call(void 0, 16).toString("hex")))
|
|
65
|
+
);
|
|
66
|
+
addIfMissing("MERCHANT_APP_ID", _nullishCoalesce(process.env.MERCHANT_APP_ID, () => ( numeric16())));
|
|
67
|
+
addIfMissing("MERCHANT_CODE", _nullishCoalesce(process.env.MERCHANT_CODE, () => ( numeric6())));
|
|
68
|
+
if (merchantPrivateKey) {
|
|
69
|
+
addIfMissing("MERCHANT_PRIVATE_KEY", `"${merchantPrivateKey}"`);
|
|
70
|
+
}
|
|
71
|
+
if (entries.length === 0) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const header = existingEnv.trim().length === 0 ? "# Telebirr Credentials\n" : "\n\n# Telebirr Credentials\n";
|
|
75
|
+
_fs2.default.writeFileSync(
|
|
76
|
+
envPath,
|
|
77
|
+
existingEnv + header + entries.join("\n") + "\n",
|
|
78
|
+
"utf8"
|
|
79
|
+
);
|
|
52
80
|
}
|
|
53
81
|
|
|
54
82
|
// src/services/requestToken.ts
|
|
@@ -382,21 +410,14 @@ function requestQueryOrder(fabricToken, merchOrderId, config) {
|
|
|
382
410
|
});
|
|
383
411
|
}
|
|
384
412
|
|
|
385
|
-
// src/client.ts
|
|
386
|
-
var
|
|
413
|
+
// src/client/c2b.ts
|
|
414
|
+
var C2B = (_class = class _C2B {
|
|
387
415
|
|
|
388
416
|
|
|
389
417
|
constructor(config) {
|
|
390
418
|
if (config.mode === "simulate") {
|
|
391
|
-
|
|
392
|
-
this.config =
|
|
393
|
-
...config,
|
|
394
|
-
appId: _nullishCoalesce(config.appId, () => ( creds.fabricAppId)),
|
|
395
|
-
appSecret: _nullishCoalesce(config.appSecret, () => ( creds.fabricAppSecret)),
|
|
396
|
-
merchantAppId: _nullishCoalesce(config.merchantAppId, () => ( creds.merchantAppId)),
|
|
397
|
-
merchantCode: _nullishCoalesce(config.merchantCode, () => ( creds.merchantCode)),
|
|
398
|
-
privateKey: creds.merchantPrivateKey
|
|
399
|
-
};
|
|
419
|
+
generateCredentials();
|
|
420
|
+
this.config = config;
|
|
400
421
|
} else {
|
|
401
422
|
this.config = config;
|
|
402
423
|
}
|
|
@@ -466,7 +487,7 @@ var TelebirrClient = (_class = class _TelebirrClient {
|
|
|
466
487
|
}
|
|
467
488
|
const now = Date.now();
|
|
468
489
|
const expiry = this.parseTelebirrDate(token.expirationDate).getTime();
|
|
469
|
-
return now >= expiry -
|
|
490
|
+
return now >= expiry - _C2B.TOKEN_EXPIRY_SAFETY_WINDOW_MS;
|
|
470
491
|
}
|
|
471
492
|
parseTelebirrDate(value) {
|
|
472
493
|
const year = Number(value.slice(0, 4));
|
|
@@ -481,5 +502,5 @@ var TelebirrClient = (_class = class _TelebirrClient {
|
|
|
481
502
|
|
|
482
503
|
|
|
483
504
|
|
|
484
|
-
exports.
|
|
505
|
+
exports.C2B = C2B; exports.generateKeys = generateKeys;
|
|
485
506
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["c:\\Users\\Dell\\Desktop\\Projects\\telebirr-nodejs\\dist\\index.cjs"],"names":[],"mappings":"AAAA;AACA,gEAAoB;AACpB,gFAAgD;AAChD,gCAAuC;AACvC;AACA;AACA;AACA;AACA
|
|
1
|
+
{"version":3,"sources":["c:\\Users\\Dell\\Desktop\\Projects\\telebirr-nodejs\\dist\\index.cjs"],"names":[],"mappings":"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A;AACA,MAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACA,MAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,EAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAA;AACA,EAAA;AACA;AACA;AACA;AACA;AACA,EAAA;AACA;AACA;AACA;AACA;AACA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,IAAA;AACA,MAAA;AACA,IAAA;AACA,IAAA;AACA,MAAA;AACA,QAAA;AACA,QAAA;AACA,UAAA;AACA,QAAA;AACA,MAAA;AACA,IAAA;AACA,MAAA;AACA,IAAA;AACA,EAAA;AACA,EAAA;AACA;AACA;AACA,EAAA;AACA,EAAA;AACA;AACA;AACA,EAAA;AACA,EAAA;AACA;AACA;AACA;AACA;AACA,EAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,IAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,MAAA;AACA,MAAA;AACA,QAAA;AACA,QAAA;AACA,UAAA;AACA,UAAA;AACA,UAAA;AACA,UAAA;AACA,QAAA;AACA,QAAA;AACA,MAAA;AACA,MAAA;AACA,QAAA;AACA,QAAA;AACA,UAAA;AACA,QAAA;AACA,QAAA;AACA,UAAA;AACA,UAAA;AACA,UAAA;AACA,YAAA;AACA,UAAA;AACA,UAAA;AACA,UAAA;AACA,YAAA;AACA,cAAA;AACA,cAAA;AACA,cAAA;AACA,cAAA;AACA,YAAA;AACA,UAAA;AACA,UAAA;AACA,YAAA;AACA,YAAA;AACA,YAAA;AACA,UAAA;AACA,QAAA;AACA,MAAA;AACA,IAAA;AACA,IAAA;AACA,MAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACA,MAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,EAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,IAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,MAAA;AACA,MAAA;AACA,QAAA;AACA,QAAA;AACA,UAAA;AACA,UAAA;AACA,UAAA;AACA,UAAA;AACA,QAAA;AACA,QAAA;AACA,MAAA;AACA,MAAA;AACA,QAAA;AACA,QAAA;AACA,UAAA;AACA,QAAA;AACA,QAAA;AACA,UAAA;AACA,UAAA;AACA,UAAA;AACA,YAAA;AACA,UAAA;AACA,UAAA;AACA,UAAA;AACA,YAAA;AACA,cAAA;AACA,cAAA;AACA,cAAA;AACA,cAAA;AACA,YAAA;AACA,UAAA;AACA,UAAA;AACA,YAAA;AACA,YAAA;AACA,YAAA;AACA,UAAA;AACA,QAAA;AACA,MAAA;AACA,IAAA;AACA,IAAA;AACA,MAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACA,MAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,EAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,IAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,MAAA;AACA,MAAA;AACA,QAAA;AACA,QAAA;AACA,UAAA;AACA,UAAA;AACA,UAAA;AACA,UAAA;AACA,QAAA;AACA,QAAA;AACA,MAAA;AACA,MAAA;AACA,QAAA;AACA,QAAA;AACA,UAAA;AACA,QAAA;AACA,QAAA;AACA,UAAA;AACA,UAAA;AACA,UAAA;AACA,YAAA;AACA,UAAA;AACA,UAAA;AACA,UAAA;AACA,YAAA;AACA,cAAA;AACA,cAAA;AACA,cAAA;AACA,cAAA;AACA,YAAA;AACA,UAAA;AACA,UAAA;AACA,YAAA;AACA,YAAA;AACA,YAAA;AACA,UAAA;AACA,QAAA;AACA,MAAA;AACA,IAAA;AACA,IAAA;AACA,MAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACA,MAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,EAAA;AACA;AACA;AACA;AACA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,MAAA;AACA,MAAA;AACA,IAAA;AACA,MAAA;AACA,IAAA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,MAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,IAAA;AACA,IAAA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,MAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,EAAA;AACA;AACA;AACA;AACA;AACA","file":"C:\\Users\\Dell\\Desktop\\Projects\\telebirr-nodejs\\dist\\index.cjs","sourcesContent":[null]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
type TelebirrMode = "simulate" | "sandbox" | "production";
|
|
2
|
-
type IntegrationOption = "C2B" | "B2B";
|
|
3
2
|
interface TelebirrConfig {
|
|
4
3
|
appId: string;
|
|
5
4
|
appSecret: string;
|
|
@@ -10,7 +9,6 @@ interface TelebirrConfig {
|
|
|
10
9
|
redirectUrl: string;
|
|
11
10
|
mode: TelebirrMode;
|
|
12
11
|
http: boolean;
|
|
13
|
-
integrationOption: IntegrationOption;
|
|
14
12
|
}
|
|
15
13
|
|
|
16
14
|
interface GenerateCheckoutUrlInput {
|
|
@@ -76,7 +74,7 @@ interface RefundResponse {
|
|
|
76
74
|
};
|
|
77
75
|
}
|
|
78
76
|
|
|
79
|
-
declare class
|
|
77
|
+
declare class C2B {
|
|
80
78
|
private token?;
|
|
81
79
|
private config;
|
|
82
80
|
constructor(config: TelebirrConfig);
|
|
@@ -101,4 +99,4 @@ declare function generateKeys(options?: KeyPairOptions): {
|
|
|
101
99
|
publicKeyPath: string;
|
|
102
100
|
};
|
|
103
101
|
|
|
104
|
-
export {
|
|
102
|
+
export { C2B, type TelebirrConfig, generateKeys };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
type TelebirrMode = "simulate" | "sandbox" | "production";
|
|
2
|
-
type IntegrationOption = "C2B" | "B2B";
|
|
3
2
|
interface TelebirrConfig {
|
|
4
3
|
appId: string;
|
|
5
4
|
appSecret: string;
|
|
@@ -10,7 +9,6 @@ interface TelebirrConfig {
|
|
|
10
9
|
redirectUrl: string;
|
|
11
10
|
mode: TelebirrMode;
|
|
12
11
|
http: boolean;
|
|
13
|
-
integrationOption: IntegrationOption;
|
|
14
12
|
}
|
|
15
13
|
|
|
16
14
|
interface GenerateCheckoutUrlInput {
|
|
@@ -76,7 +74,7 @@ interface RefundResponse {
|
|
|
76
74
|
};
|
|
77
75
|
}
|
|
78
76
|
|
|
79
|
-
declare class
|
|
77
|
+
declare class C2B {
|
|
80
78
|
private token?;
|
|
81
79
|
private config;
|
|
82
80
|
constructor(config: TelebirrConfig);
|
|
@@ -101,4 +99,4 @@ declare function generateKeys(options?: KeyPairOptions): {
|
|
|
101
99
|
publicKeyPath: string;
|
|
102
100
|
};
|
|
103
101
|
|
|
104
|
-
export {
|
|
102
|
+
export { C2B, type TelebirrConfig, generateKeys };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// src/utils/credentials.ts
|
|
2
2
|
import fs2 from "fs";
|
|
3
|
+
import path2 from "path";
|
|
3
4
|
import { randomUUID, randomBytes } from "crypto";
|
|
4
5
|
import { customAlphabet } from "nanoid";
|
|
5
6
|
|
|
@@ -39,16 +40,43 @@ function generateKeys(options = {}) {
|
|
|
39
40
|
// src/utils/credentials.ts
|
|
40
41
|
var numeric16 = customAlphabet("0123456789", 16);
|
|
41
42
|
var numeric6 = customAlphabet("0123456789", 6);
|
|
43
|
+
var ENV_FILE_NAME = ".env";
|
|
42
44
|
function generateCredentials() {
|
|
43
|
-
const
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
45
|
+
const envPath = path2.join(process.cwd(), ENV_FILE_NAME);
|
|
46
|
+
const existingEnv = fs2.existsSync(envPath) ? fs2.readFileSync(envPath, "utf8") : "";
|
|
47
|
+
const existingKeys = new Set(
|
|
48
|
+
existingEnv.split("\n").map((line) => line.split("=")[0].trim()).filter(Boolean)
|
|
49
|
+
);
|
|
50
|
+
const entries = [];
|
|
51
|
+
const addIfMissing = (key, value) => {
|
|
52
|
+
if (!existingKeys.has(key)) {
|
|
53
|
+
entries.push(`${key}=${value}`);
|
|
54
|
+
}
|
|
51
55
|
};
|
|
56
|
+
let merchantPrivateKey = "";
|
|
57
|
+
if (!existingKeys.has("MERCHANT_PRIVATE_KEY")) {
|
|
58
|
+
const { privateKeyPath } = generateKeys();
|
|
59
|
+
merchantPrivateKey = fs2.readFileSync(privateKeyPath, "utf8").replace(/\n/g, "\\n");
|
|
60
|
+
}
|
|
61
|
+
addIfMissing("FABRIC_APP_ID", process.env.FABRIC_APP_ID ?? randomUUID());
|
|
62
|
+
addIfMissing(
|
|
63
|
+
"FABRIC_APP_SECRET",
|
|
64
|
+
process.env.FABRIC_APP_SECRET ?? randomBytes(16).toString("hex")
|
|
65
|
+
);
|
|
66
|
+
addIfMissing("MERCHANT_APP_ID", process.env.MERCHANT_APP_ID ?? numeric16());
|
|
67
|
+
addIfMissing("MERCHANT_CODE", process.env.MERCHANT_CODE ?? numeric6());
|
|
68
|
+
if (merchantPrivateKey) {
|
|
69
|
+
addIfMissing("MERCHANT_PRIVATE_KEY", `"${merchantPrivateKey}"`);
|
|
70
|
+
}
|
|
71
|
+
if (entries.length === 0) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const header = existingEnv.trim().length === 0 ? "# Telebirr Credentials\n" : "\n\n# Telebirr Credentials\n";
|
|
75
|
+
fs2.writeFileSync(
|
|
76
|
+
envPath,
|
|
77
|
+
existingEnv + header + entries.join("\n") + "\n",
|
|
78
|
+
"utf8"
|
|
79
|
+
);
|
|
52
80
|
}
|
|
53
81
|
|
|
54
82
|
// src/services/requestToken.ts
|
|
@@ -382,21 +410,14 @@ function requestQueryOrder(fabricToken, merchOrderId, config) {
|
|
|
382
410
|
});
|
|
383
411
|
}
|
|
384
412
|
|
|
385
|
-
// src/client.ts
|
|
386
|
-
var
|
|
413
|
+
// src/client/c2b.ts
|
|
414
|
+
var C2B = class _C2B {
|
|
387
415
|
token;
|
|
388
416
|
config;
|
|
389
417
|
constructor(config) {
|
|
390
418
|
if (config.mode === "simulate") {
|
|
391
|
-
|
|
392
|
-
this.config =
|
|
393
|
-
...config,
|
|
394
|
-
appId: config.appId ?? creds.fabricAppId,
|
|
395
|
-
appSecret: config.appSecret ?? creds.fabricAppSecret,
|
|
396
|
-
merchantAppId: config.merchantAppId ?? creds.merchantAppId,
|
|
397
|
-
merchantCode: config.merchantCode ?? creds.merchantCode,
|
|
398
|
-
privateKey: creds.merchantPrivateKey
|
|
399
|
-
};
|
|
419
|
+
generateCredentials();
|
|
420
|
+
this.config = config;
|
|
400
421
|
} else {
|
|
401
422
|
this.config = config;
|
|
402
423
|
}
|
|
@@ -466,7 +487,7 @@ var TelebirrClient = class _TelebirrClient {
|
|
|
466
487
|
}
|
|
467
488
|
const now = Date.now();
|
|
468
489
|
const expiry = this.parseTelebirrDate(token.expirationDate).getTime();
|
|
469
|
-
return now >= expiry -
|
|
490
|
+
return now >= expiry - _C2B.TOKEN_EXPIRY_SAFETY_WINDOW_MS;
|
|
470
491
|
}
|
|
471
492
|
parseTelebirrDate(value) {
|
|
472
493
|
const year = Number(value.slice(0, 4));
|
|
@@ -479,7 +500,7 @@ var TelebirrClient = class _TelebirrClient {
|
|
|
479
500
|
}
|
|
480
501
|
};
|
|
481
502
|
export {
|
|
482
|
-
|
|
503
|
+
C2B,
|
|
483
504
|
generateKeys
|
|
484
505
|
};
|
|
485
506
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/credentials.ts","../src/utils/keys.ts","../src/services/requestToken.ts","../src/constants/urls.ts","../src/services/requestCreateOrder.ts","../src/utils/nonce.ts","../src/utils/timestamp.ts","../src/utils/signature.ts","../src/services/requestRefundOrder.ts","../src/services/requestQueryOrder.ts","../src/client.ts"],"sourcesContent":["import fs from \"fs\";\r\nimport { randomUUID, randomBytes } from \"crypto\";\r\nimport { customAlphabet } from \"nanoid\";\r\nimport { generateKeys } from \"./keys\";\r\n\r\nconst numeric16 = customAlphabet(\"0123456789\", 16);\r\nconst numeric6 = customAlphabet(\"0123456789\", 6);\r\n\r\nexport interface SimulatorCredentials {\r\n fabricAppId: string;\r\n fabricAppSecret: string;\r\n merchantAppId: string;\r\n merchantCode: string;\r\n merchantPrivateKey: string;\r\n}\r\n\r\nexport function generateCredentials(): SimulatorCredentials {\r\n const { privateKeyPath } = generateKeys();\r\n\r\n const merchantPrivateKey = fs.readFileSync(privateKeyPath, \"utf8\");\r\n\r\n return {\r\n fabricAppId: randomUUID(),\r\n fabricAppSecret: randomBytes(16).toString(\"hex\"),\r\n merchantAppId: numeric16(),\r\n merchantCode: numeric6(),\r\n merchantPrivateKey,\r\n };\r\n}\r\n","import { generateKeyPairSync } from \"crypto\";\r\nimport fs from \"fs\";\r\nimport path from \"path\";\r\n\r\nexport interface KeyPairOptions {\r\n dir?: string; // default: process.cwd()\r\n privateKeyName?: string;\r\n publicKeyName?: string;\r\n overwrite?: boolean; // default: false\r\n}\r\n\r\nexport function generateKeys(options: KeyPairOptions = {}): {\r\n privateKeyPath: string;\r\n publicKeyPath: string;\r\n} {\r\n const {\r\n dir = process.cwd(),\r\n privateKeyName = \"telebirr_private.pem\",\r\n publicKeyName = \"telebirr_public.pem\",\r\n overwrite = false,\r\n } = options;\r\n\r\n const privateKeyPath = path.join(dir, privateKeyName);\r\n const publicKeyPath = path.join(dir, publicKeyName);\r\n\r\n const exists = fs.existsSync(privateKeyPath) && fs.existsSync(publicKeyPath);\r\n\r\n if (exists && !overwrite) {\r\n return { privateKeyPath, publicKeyPath };\r\n }\r\n\r\n const { privateKey, publicKey } = generateKeyPairSync(\"rsa\", {\r\n modulusLength: 2048,\r\n publicKeyEncoding: {\r\n type: \"pkcs1\",\r\n format: \"pem\",\r\n },\r\n privateKeyEncoding: {\r\n type: \"pkcs1\",\r\n format: \"pem\",\r\n },\r\n });\r\n\r\n fs.writeFileSync(privateKeyPath, privateKey, { mode: 0o600 });\r\n fs.writeFileSync(publicKeyPath, publicKey);\r\n\r\n return { privateKeyPath, publicKeyPath };\r\n}\r\n","import http from \"http\";\r\nimport https from \"https\";\r\nimport { TELEBIRR_URLS } from \"../constants/urls\";\r\nimport { TelebirrConfig } from \"../types/telebirrConfig\";\r\n\r\nexport function requestToken(config: TelebirrConfig) {\r\n const isHttps = TELEBIRR_URLS[config.mode].apiBase.startsWith(\"https://\");\r\n const client = isHttps ? https : http;\r\n return new Promise((resolve, reject) => {\r\n const req = client.request(\r\n ` ${TELEBIRR_URLS[config.mode].apiBase}/payment/v1/token`,\r\n {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n \"X-APP-Key\": config.appId,\r\n },\r\n ...(isHttps && { rejectUnauthorized: false }),\r\n },\r\n (res) => {\r\n let body = \"\";\r\n\r\n res.on(\"data\", (chunk) => (body += chunk));\r\n res.on(\"end\", () => resolve(body));\r\n }\r\n );\r\n\r\n req.on(\"error\", reject);\r\n req.write(JSON.stringify({ appSecret: config.appSecret }));\r\n req.end();\r\n });\r\n}\r\n\r\n// import { AxiosInstance } from \"axios\";\r\n// import {\r\n// ApplyFabricTokenRequest,\r\n// FabricTokenResponse,\r\n// } from \"../types/fabricToken\";\r\n\r\n// export async function applyFabricToken(\r\n// client: AxiosInstance,\r\n// payload: ApplyFabricTokenRequest\r\n// ): Promise<typeof FabricTokenResponse | void> {\r\n// const appSecret = payload.appSecret;\r\n// try {\r\n// const response = await client.post<typeof FabricTokenResponse | void>(\r\n// \"/payment/v1/token\",\r\n// { appSecret }\r\n// );\r\n\r\n// return response.data;\r\n// } catch (error) {\r\n// console.log(error);\r\n// }\r\n// }\r\n","export const TELEBIRR_URLS = {\r\n sandbox: {\r\n apiBase:\r\n \"https://developerportal.ethiotelebirr.et:38443/apiaccess/payment/gateway\",\r\n webBase:\r\n \"https://developerportal.ethiotelebirr.et:38443/payment/web/paygate?\",\r\n },\r\n production: {\r\n apiBase:\r\n \"https://telebirrappcube.ethiomobilemoney.et:38443/apiaccess/payment/gateway\",\r\n webBase:\r\n \"https://telebirrappcube.ethiomobilemoney.et:38443/payment/web/paygate?\",\r\n },\r\n simulate: {\r\n apiBase: \"https://telebirr-node-simulator.onrender.com\",\r\n webBase: \"https://telebirr-node-simulator.onrender.com/web/?\",\r\n },\r\n};\r\n\r\nexport const CHECKOUT_OTHER_PARAMS = \"&version=1.0&trade_type=Checkout\";\r\n","import http from \"http\";\r\nimport https from \"https\";\r\nimport {\r\n GenerateCheckoutUrlInput,\r\n CreateOrderResponse,\r\n TelebirrPreorderRequest,\r\n} from \"../types/createOrder\";\r\nimport { createNonceStr } from \"../utils/nonce\";\r\nimport { createTimestamp } from \"../utils/timestamp\";\r\nimport { signRequest } from \"../utils/signature\";\r\nimport { TelebirrMode, IntegrationOption } from \"../types/telebirrConfig\";\r\nimport { TELEBIRR_URLS } from \"../constants/urls\";\r\n\r\nexport function requestCreateOrder(\r\n fabricToken: string,\r\n input: GenerateCheckoutUrlInput,\r\n config: {\r\n mode: TelebirrMode;\r\n appId: string;\r\n appSecret: string;\r\n merchantAppId: string;\r\n merchantCode: string;\r\n notifyUrl: string;\r\n redirectUrl: string;\r\n privateKey: string;\r\n http: boolean;\r\n integrationOption: IntegrationOption;\r\n }\r\n): Promise<{\r\n data: CreateOrderResponse;\r\n status: number;\r\n headers: http.IncomingHttpHeaders;\r\n}> {\r\n const reqBody: TelebirrPreorderRequest = {\r\n timestamp: createTimestamp(),\r\n nonce_str: createNonceStr(),\r\n method: \"payment.preorder\",\r\n version: \"1.0\",\r\n biz_content: {\r\n appid: config.merchantAppId,\r\n merch_code: config.merchantCode,\r\n merch_order_id: input.merchOrderId,\r\n notify_url: config.notifyUrl,\r\n redirect_url: config.redirectUrl,\r\n trade_type: \"Checkout\",\r\n title: input.title,\r\n total_amount: input.amount,\r\n trans_currency: \"ETB\",\r\n timeout_express: \"120m\",\r\n business_type: \"BuyGoods\",\r\n payee_type: \"3000\",\r\n payee_identifier: config.merchantCode,\r\n payee_identifier_type: \"04\",\r\n callback_info: \"From web\",\r\n },\r\n };\r\n\r\n reqBody.sign = signRequest(reqBody, config.privateKey);\r\n reqBody.sign_type = \"SHA256WithRSA\";\r\n\r\n const payload = JSON.stringify(reqBody);\r\n\r\n const baseUrl = TELEBIRR_URLS[config.mode].apiBase;\r\n const isHttps = baseUrl.startsWith(\"https://\");\r\n const client = isHttps ? https : http;\r\n\r\n return new Promise((resolve, reject) => {\r\n const req = client.request(\r\n `${baseUrl}/payment/v1/merchant/preOrder`,\r\n {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n \"Content-Length\": Buffer.byteLength(payload),\r\n \"X-APP-Key\": config.appId,\r\n Authorization: fabricToken,\r\n },\r\n ...(isHttps && { rejectUnauthorized: false }),\r\n },\r\n (res) => {\r\n let raw = \"\";\r\n\r\n res.on(\"data\", (chunk) => {\r\n raw += chunk;\r\n });\r\n\r\n res.on(\"end\", () => {\r\n const status = res.statusCode || 0;\r\n let parsed: any = raw;\r\n\r\n try {\r\n parsed = JSON.parse(raw);\r\n } catch {\r\n // keep raw string if JSON parsing fails\r\n }\r\n\r\n if (status < 200 || status >= 300) {\r\n return reject({\r\n message: \"Telebirr preorder request failed\",\r\n status,\r\n data: parsed,\r\n headers: res.headers,\r\n });\r\n }\r\n\r\n resolve({\r\n data: parsed,\r\n status,\r\n headers: res.headers,\r\n });\r\n });\r\n }\r\n );\r\n\r\n req.on(\"error\", (err) => {\r\n reject({\r\n message: \"Telebirr preorder network error\",\r\n cause: err,\r\n code: (err as any).code,\r\n });\r\n });\r\n\r\n req.write(payload);\r\n req.end();\r\n });\r\n}\r\n","import { randomBytes } from \"crypto\";\r\n\r\nexport function createNonceStr(): string {\r\n const bytes = Math.ceil(16);\r\n return randomBytes(bytes).toString(\"hex\").slice(0, 32);\r\n}\r\n","export function createTimestamp(): string {\r\n return Math.floor(Date.now() / 1000).toString();\r\n}\r\n","import crypto from \"crypto\";\r\n\r\nfunction flattenParams(params: Record<string, any>): Record<string, string> {\r\n const flat: Record<string, string> = {};\r\n\r\n for (const key in params) {\r\n const value = params[key];\r\n\r\n if (\r\n value === undefined ||\r\n value === null ||\r\n value === \"\" ||\r\n key === \"sign\" ||\r\n key === \"signType\" ||\r\n key === \"sign_type\"\r\n ) {\r\n continue;\r\n }\r\n\r\n if (key === \"biz_content\" && typeof value === \"object\") {\r\n for (const bizKey in value) {\r\n const bizValue = value[bizKey];\r\n if (bizValue !== undefined && bizValue !== null && bizValue !== \"\") {\r\n flat[bizKey] = String(bizValue);\r\n }\r\n }\r\n } else {\r\n flat[key] = String(value);\r\n }\r\n }\r\n\r\n return flat;\r\n}\r\n\r\nexport function buildSignString(params: Record<string, any>): string {\r\n const flat = flattenParams(params);\r\n\r\n return Object.keys(flat)\r\n .sort()\r\n .map((key) => `${key}=${flat[key]}`)\r\n .join(\"&\");\r\n}\r\n\r\nexport function signRequest(\r\n data: Record<string, any>,\r\n privateKey: string\r\n): string {\r\n const signString = buildSignString(data);\r\n\r\n return crypto\r\n .createSign(\"RSA-SHA256\")\r\n .update(signString, \"utf8\")\r\n .sign(privateKey, \"base64\");\r\n}\r\n","import http from \"http\";\r\nimport https from \"https\";\r\nimport { createNonceStr } from \"../utils/nonce\";\r\nimport { createTimestamp } from \"../utils/timestamp\";\r\nimport { signRequest } from \"../utils/signature\";\r\nimport { TelebirrMode, IntegrationOption } from \"../types/telebirrConfig\";\r\nimport {\r\n RefundInput,\r\n RefundResponse,\r\n TelebirrRefundRequest,\r\n} from \"../types/refund\";\r\nimport { TELEBIRR_URLS } from \"../constants/urls\";\r\n\r\nexport function requestRefund(\r\n fabricToken: string,\r\n input: RefundInput,\r\n config: {\r\n mode: TelebirrMode;\r\n appId: string;\r\n merchantAppId: string;\r\n merchantCode: string;\r\n privateKey: string;\r\n http: boolean;\r\n integrationOption: IntegrationOption;\r\n }\r\n): Promise<{\r\n data: RefundResponse;\r\n status: number;\r\n headers: http.IncomingHttpHeaders;\r\n}> {\r\n const reqBody: TelebirrRefundRequest = {\r\n timestamp: createTimestamp(),\r\n nonce_str: createNonceStr(),\r\n method: \"payment.refund\",\r\n version: \"1.0\",\r\n biz_content: {\r\n appid: config.merchantAppId,\r\n merch_code: config.merchantCode,\r\n merch_order_id: input.merchOrderId,\r\n trans_currency: \"ETB\",\r\n actual_amount: input.amount,\r\n refund_request_no: input.refundRequestNo,\r\n refund_reason: input.refundReason,\r\n },\r\n };\r\n\r\n reqBody.sign = signRequest(reqBody, config.privateKey);\r\n reqBody.sign_type = \"SHA256WithRSA\";\r\n\r\n const payload = JSON.stringify(reqBody);\r\n\r\n const baseUrl = TELEBIRR_URLS[config.mode].apiBase;\r\n const isHttps = baseUrl.startsWith(\"https://\");\r\n const client = isHttps ? https : http;\r\n\r\n return new Promise((resolve, reject) => {\r\n const req = client.request(\r\n `${baseUrl}/payment/v1/merchant/refund`,\r\n {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n \"Content-Length\": Buffer.byteLength(payload),\r\n \"X-APP-Key\": config.appId,\r\n Authorization: fabricToken,\r\n },\r\n ...(isHttps && { rejectUnauthorized: false }),\r\n },\r\n (res) => {\r\n let raw = \"\";\r\n\r\n res.on(\"data\", (chunk) => {\r\n raw += chunk;\r\n });\r\n\r\n res.on(\"end\", () => {\r\n const status = res.statusCode || 0;\r\n let parsed: any = raw;\r\n\r\n try {\r\n parsed = JSON.parse(raw);\r\n } catch {\r\n // keep raw string if JSON parsing fails\r\n }\r\n\r\n if (status < 200 || status >= 300) {\r\n return reject({\r\n message: \"Telebirr refund request failed\",\r\n status,\r\n data: parsed,\r\n headers: res.headers,\r\n });\r\n }\r\n\r\n resolve({\r\n data: parsed,\r\n status,\r\n headers: res.headers,\r\n });\r\n });\r\n }\r\n );\r\n\r\n req.on(\"error\", (err) => {\r\n reject({\r\n message: \"Telebirr refund network error\",\r\n cause: err,\r\n code: (err as any).code,\r\n });\r\n });\r\n\r\n req.write(payload);\r\n req.end();\r\n });\r\n}\r\n","import http from \"http\";\r\nimport https from \"https\";\r\nimport {\r\n TelebirrQueryorderRequest,\r\n QueryOrderResponse,\r\n} from \"../types/queryOrder\";\r\nimport { createNonceStr } from \"../utils/nonce\";\r\nimport { createTimestamp } from \"../utils/timestamp\";\r\nimport { signRequest } from \"../utils/signature\";\r\nimport { TelebirrMode, IntegrationOption } from \"../types/telebirrConfig\";\r\nimport { TELEBIRR_URLS } from \"../constants/urls\";\r\n\r\nexport function requestQueryOrder(\r\n fabricToken: string,\r\n merchOrderId: string,\r\n config: {\r\n appId: string;\r\n appSecret: string;\r\n merchantAppId: string;\r\n merchantCode: string;\r\n privateKey: string;\r\n notifyUrl: string;\r\n redirectUrl: string;\r\n mode: TelebirrMode;\r\n http: boolean;\r\n integrationOption: IntegrationOption;\r\n }\r\n): Promise<{\r\n data: QueryOrderResponse;\r\n status: number;\r\n headers: http.IncomingHttpHeaders;\r\n}> {\r\n const reqBody: TelebirrQueryorderRequest = {\r\n timestamp: createTimestamp(),\r\n nonce_str: createNonceStr(),\r\n method: \"payment.queryorder\",\r\n version: \"1.0\",\r\n biz_content: {\r\n appid: config.merchantAppId,\r\n merch_code: config.merchantCode,\r\n merch_order_id: merchOrderId,\r\n },\r\n };\r\n\r\n reqBody.sign = signRequest(reqBody, config.privateKey);\r\n reqBody.sign_type = \"SHA256WithRSA\";\r\n\r\n const payload = JSON.stringify(reqBody);\r\n\r\n const baseUrl = TELEBIRR_URLS[config.mode].apiBase;\r\n const isHttps = baseUrl.startsWith(\"https://\");\r\n const client = isHttps ? https : http;\r\n\r\n return new Promise((resolve, reject) => {\r\n const req = client.request(\r\n `${baseUrl}/payment/v1/merchant/queryOrder`,\r\n {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n \"Content-Length\": Buffer.byteLength(payload),\r\n \"X-APP-Key\": config.appId,\r\n Authorization: fabricToken,\r\n },\r\n ...(isHttps && { rejectUnauthorized: false }),\r\n },\r\n (res) => {\r\n let raw = \"\";\r\n\r\n res.on(\"data\", (chunk) => {\r\n raw += chunk;\r\n });\r\n\r\n res.on(\"end\", () => {\r\n const status = res.statusCode || 0;\r\n let parsed: any = raw;\r\n\r\n try {\r\n parsed = JSON.parse(raw);\r\n } catch {\r\n // keep raw if parsing fails\r\n }\r\n\r\n if (status < 200 || status >= 300) {\r\n return reject({\r\n message: \"Telebirr queryOrder request failed\",\r\n status,\r\n data: parsed,\r\n headers: res.headers,\r\n });\r\n }\r\n\r\n resolve({\r\n data: parsed,\r\n status,\r\n headers: res.headers,\r\n });\r\n });\r\n }\r\n );\r\n\r\n req.on(\"error\", (err) => {\r\n reject({\r\n message: \"Telebirr queryOrder network error\",\r\n cause: err,\r\n code: (err as any).code,\r\n });\r\n });\r\n\r\n req.write(payload);\r\n req.end();\r\n });\r\n}\r\n","import { TelebirrConfig } from \"./types/telebirrConfig\";\r\nimport { FabricTokenResponse } from \"./types/fabricToken\";\r\nimport { GenerateCheckoutUrlInput } from \"./types/createOrder\";\r\nimport { generateCredentials } from \"./utils/credentials\";\r\nimport { QueryOrderResponse } from \"./types/queryOrder\";\r\nimport { RefundInput, RefundResponse } from \"./types/refund\";\r\nimport { requestToken } from \"./services/requestToken\";\r\nimport { requestCreateOrder } from \"./services/requestCreateOrder\";\r\nimport { requestRefund } from \"./services/requestRefundOrder\";\r\nimport { requestQueryOrder } from \"./services/requestQueryOrder\";\r\nimport { TELEBIRR_URLS, CHECKOUT_OTHER_PARAMS } from \"./constants/urls\";\r\nimport { signRequest } from \"./utils/signature\";\r\nimport { createTimestamp } from \"./utils/timestamp\";\r\nimport { createNonceStr } from \"./utils/nonce\";\r\n\r\nexport class TelebirrClient {\r\n private token?: typeof FabricTokenResponse;\r\n private config: TelebirrConfig;\r\n\r\n constructor(config: TelebirrConfig) {\r\n if (config.mode === \"simulate\") {\r\n const creds = generateCredentials();\r\n\r\n this.config = {\r\n ...config,\r\n appId: config.appId ?? creds.fabricAppId,\r\n appSecret: config.appSecret ?? creds.fabricAppSecret,\r\n merchantAppId: config.merchantAppId ?? creds.merchantAppId,\r\n merchantCode: config.merchantCode ?? creds.merchantCode,\r\n privateKey: creds.merchantPrivateKey,\r\n };\r\n } else {\r\n this.config = config;\r\n }\r\n }\r\n\r\n async getFabricToken(): Promise<any> {\r\n if (this.token && !this.isTokenExpired(this.token)) {\r\n return this.token;\r\n }\r\n\r\n let token: any = await requestToken(this.config);\r\n token = JSON.parse(token);\r\n if (!token) return;\r\n this.token = token;\r\n return token;\r\n }\r\n\r\n private createCheckoutUrl(prepayId: string): string {\r\n const map = {\r\n appid: this.config.merchantAppId,\r\n merch_code: this.config.merchantCode,\r\n nonce_str: createNonceStr(),\r\n prepay_id: prepayId,\r\n timestamp: createTimestamp(),\r\n };\r\n\r\n const sign = signRequest(map, this.config.privateKey);\r\n\r\n const rawRequest = [\r\n `appid=${map.appid}`,\r\n `merch_code=${map.merch_code}`,\r\n `nonce_str=${map.nonce_str}`,\r\n `prepay_id=${map.prepay_id}`,\r\n `timestamp=${map.timestamp}`,\r\n `sign=${sign}`,\r\n `sign_type=SHA256WithRSA`,\r\n ].join(\"&\");\r\n\r\n const webBase = TELEBIRR_URLS[this.config.mode].webBase;\r\n\r\n return webBase + rawRequest + CHECKOUT_OTHER_PARAMS;\r\n }\r\n async preOrder(input: GenerateCheckoutUrlInput): Promise<string | void> {\r\n const token = await this.getFabricToken();\r\n\r\n if (!token) return;\r\n\r\n let response: any = await requestCreateOrder(\r\n token.token,\r\n input,\r\n this.config\r\n );\r\n if (!response) return;\r\n\r\n return this.createCheckoutUrl(response.data.biz_content.prepay_id);\r\n }\r\n\r\n async queryOrder(input: string): Promise<QueryOrderResponse | void> {\r\n let token = await this.getFabricToken();\r\n\r\n if (!token) return;\r\n\r\n const response: any = await requestQueryOrder(\r\n token.token,\r\n input,\r\n this.config\r\n );\r\n\r\n return response.data;\r\n }\r\n async refundOrder(input: RefundInput): Promise<RefundResponse | void> {\r\n const token = await this.getFabricToken();\r\n if (!token) return;\r\n const response: any = await requestRefund(token.token, input, this.config);\r\n\r\n return response.data;\r\n }\r\n\r\n private static readonly TOKEN_EXPIRY_SAFETY_WINDOW_MS = 5 * 60 * 1000;\r\n\r\n private isTokenExpired(token?: typeof FabricTokenResponse): boolean {\r\n if (!token) {\r\n return true;\r\n }\r\n\r\n const now = Date.now();\r\n const expiry = this.parseTelebirrDate(token.expirationDate).getTime();\r\n\r\n return now >= expiry - TelebirrClient.TOKEN_EXPIRY_SAFETY_WINDOW_MS;\r\n }\r\n\r\n private parseTelebirrDate(value: string): Date {\r\n const year = Number(value.slice(0, 4));\r\n const month = Number(value.slice(4, 6)) - 1;\r\n const day = Number(value.slice(6, 8));\r\n const hour = Number(value.slice(8, 10));\r\n const minute = Number(value.slice(10, 12));\r\n const second = Number(value.slice(12, 14));\r\n\r\n return new Date(Date.UTC(year, month, day, hour, minute, second));\r\n }\r\n}\r\n"],"mappings":"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","names":["fs","fs","http","https","randomBytes","https","http","http","https","https","http","http","https","https","http"]}
|
|
1
|
+
{"version":3,"sources":["../src/utils/credentials.ts","../src/utils/keys.ts","../src/services/requestToken.ts","../src/constants/urls.ts","../src/services/requestCreateOrder.ts","../src/utils/nonce.ts","../src/utils/timestamp.ts","../src/utils/signature.ts","../src/services/requestRefundOrder.ts","../src/services/requestQueryOrder.ts","../src/client/c2b.ts"],"sourcesContent":["import fs from \"fs\";\r\nimport path from \"path\";\r\nimport { randomUUID, randomBytes } from \"crypto\";\r\nimport { customAlphabet } from \"nanoid\";\r\nimport { generateKeys } from \"./keys\";\r\n\r\nconst numeric16 = customAlphabet(\"0123456789\", 16);\r\nconst numeric6 = customAlphabet(\"0123456789\", 6);\r\n\r\nconst ENV_FILE_NAME = \".env\";\r\n\r\nexport function generateCredentials(): void {\r\n const envPath = path.join(process.cwd(), ENV_FILE_NAME);\r\n\r\n const existingEnv = fs.existsSync(envPath)\r\n ? fs.readFileSync(envPath, \"utf8\")\r\n : \"\";\r\n\r\n // Collect existing keys\r\n const existingKeys = new Set(\r\n existingEnv\r\n .split(\"\\n\")\r\n .map((line) => line.split(\"=\")[0].trim())\r\n .filter(Boolean)\r\n );\r\n\r\n const entries: string[] = [];\r\n\r\n // Helper\r\n const addIfMissing = (key: string, value: string) => {\r\n if (!existingKeys.has(key)) {\r\n entries.push(`${key}=${value}`);\r\n }\r\n };\r\n\r\n // Generate key only if needed\r\n let merchantPrivateKey = \"\";\r\n if (!existingKeys.has(\"MERCHANT_PRIVATE_KEY\")) {\r\n const { privateKeyPath } = generateKeys();\r\n merchantPrivateKey = fs\r\n .readFileSync(privateKeyPath, \"utf8\")\r\n .replace(/\\n/g, \"\\\\n\");\r\n }\r\n\r\n addIfMissing(\"FABRIC_APP_ID\", process.env.FABRIC_APP_ID ?? randomUUID());\r\n\r\n addIfMissing(\r\n \"FABRIC_APP_SECRET\",\r\n process.env.FABRIC_APP_SECRET ?? randomBytes(16).toString(\"hex\")\r\n );\r\n\r\n addIfMissing(\"MERCHANT_APP_ID\", process.env.MERCHANT_APP_ID ?? numeric16());\r\n\r\n addIfMissing(\"MERCHANT_CODE\", process.env.MERCHANT_CODE ?? numeric6());\r\n\r\n if (merchantPrivateKey) {\r\n addIfMissing(\"MERCHANT_PRIVATE_KEY\", `\"${merchantPrivateKey}\"`);\r\n }\r\n\r\n // Nothing to write\r\n if (entries.length === 0) {\r\n return;\r\n }\r\n\r\n const header =\r\n existingEnv.trim().length === 0\r\n ? \"# Telebirr Credentials\\n\"\r\n : \"\\n\\n# Telebirr Credentials\\n\";\r\n\r\n fs.writeFileSync(\r\n envPath,\r\n existingEnv + header + entries.join(\"\\n\") + \"\\n\",\r\n \"utf8\"\r\n );\r\n}\r\n","import { generateKeyPairSync } from \"crypto\";\r\nimport fs from \"fs\";\r\nimport path from \"path\";\r\n\r\nexport interface KeyPairOptions {\r\n dir?: string; // default: process.cwd()\r\n privateKeyName?: string;\r\n publicKeyName?: string;\r\n overwrite?: boolean; // default: false\r\n}\r\n\r\nexport function generateKeys(options: KeyPairOptions = {}): {\r\n privateKeyPath: string;\r\n publicKeyPath: string;\r\n} {\r\n const {\r\n dir = process.cwd(),\r\n privateKeyName = \"telebirr_private.pem\",\r\n publicKeyName = \"telebirr_public.pem\",\r\n overwrite = false,\r\n } = options;\r\n\r\n const privateKeyPath = path.join(dir, privateKeyName);\r\n const publicKeyPath = path.join(dir, publicKeyName);\r\n\r\n const exists = fs.existsSync(privateKeyPath) && fs.existsSync(publicKeyPath);\r\n\r\n if (exists && !overwrite) {\r\n return { privateKeyPath, publicKeyPath };\r\n }\r\n\r\n const { privateKey, publicKey } = generateKeyPairSync(\"rsa\", {\r\n modulusLength: 2048,\r\n publicKeyEncoding: {\r\n type: \"pkcs1\",\r\n format: \"pem\",\r\n },\r\n privateKeyEncoding: {\r\n type: \"pkcs1\",\r\n format: \"pem\",\r\n },\r\n });\r\n\r\n fs.writeFileSync(privateKeyPath, privateKey, { mode: 0o600 });\r\n fs.writeFileSync(publicKeyPath, publicKey);\r\n\r\n return { privateKeyPath, publicKeyPath };\r\n}\r\n","import http from \"http\";\r\nimport https from \"https\";\r\nimport { TELEBIRR_URLS } from \"../constants/urls\";\r\nimport { TelebirrConfig } from \"../types/telebirrConfig\";\r\n\r\nexport function requestToken(config: TelebirrConfig) {\r\n const isHttps = TELEBIRR_URLS[config.mode].apiBase.startsWith(\"https://\");\r\n const client = isHttps ? https : http;\r\n return new Promise((resolve, reject) => {\r\n const req = client.request(\r\n ` ${TELEBIRR_URLS[config.mode].apiBase}/payment/v1/token`,\r\n {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n \"X-APP-Key\": config.appId,\r\n },\r\n ...(isHttps && { rejectUnauthorized: false }),\r\n },\r\n (res) => {\r\n let body = \"\";\r\n\r\n res.on(\"data\", (chunk) => (body += chunk));\r\n res.on(\"end\", () => resolve(body));\r\n }\r\n );\r\n\r\n req.on(\"error\", reject);\r\n req.write(JSON.stringify({ appSecret: config.appSecret }));\r\n req.end();\r\n });\r\n}\r\n","export const TELEBIRR_URLS = {\r\n sandbox: {\r\n apiBase:\r\n \"https://developerportal.ethiotelebirr.et:38443/apiaccess/payment/gateway\",\r\n webBase:\r\n \"https://developerportal.ethiotelebirr.et:38443/payment/web/paygate?\",\r\n },\r\n production: {\r\n apiBase:\r\n \"https://telebirrappcube.ethiomobilemoney.et:38443/apiaccess/payment/gateway\",\r\n webBase:\r\n \"https://telebirrappcube.ethiomobilemoney.et:38443/payment/web/paygate?\",\r\n },\r\n simulate: {\r\n apiBase: \"https://telebirr-node-simulator.onrender.com\",\r\n webBase: \"https://telebirr-node-simulator.onrender.com/web/?\",\r\n },\r\n};\r\n\r\nexport const CHECKOUT_OTHER_PARAMS = \"&version=1.0&trade_type=Checkout\";\r\n","import http from \"http\";\r\nimport https from \"https\";\r\nimport {\r\n GenerateCheckoutUrlInput,\r\n CreateOrderResponse,\r\n TelebirrPreorderRequest,\r\n} from \"../types/createOrder\";\r\nimport { createNonceStr } from \"../utils/nonce\";\r\nimport { createTimestamp } from \"../utils/timestamp\";\r\nimport { signRequest } from \"../utils/signature\";\r\nimport { TelebirrMode } from \"../types/telebirrConfig\";\r\nimport { TELEBIRR_URLS } from \"../constants/urls\";\r\n\r\nexport function requestCreateOrder(\r\n fabricToken: string,\r\n input: GenerateCheckoutUrlInput,\r\n config: {\r\n mode: TelebirrMode;\r\n appId: string;\r\n appSecret: string;\r\n merchantAppId: string;\r\n merchantCode: string;\r\n notifyUrl: string;\r\n redirectUrl: string;\r\n privateKey: string;\r\n http: boolean;\r\n }\r\n): Promise<{\r\n data: CreateOrderResponse;\r\n status: number;\r\n headers: http.IncomingHttpHeaders;\r\n}> {\r\n const reqBody: TelebirrPreorderRequest = {\r\n timestamp: createTimestamp(),\r\n nonce_str: createNonceStr(),\r\n method: \"payment.preorder\",\r\n version: \"1.0\",\r\n biz_content: {\r\n appid: config.merchantAppId,\r\n merch_code: config.merchantCode,\r\n merch_order_id: input.merchOrderId,\r\n notify_url: config.notifyUrl,\r\n redirect_url: config.redirectUrl,\r\n trade_type: \"Checkout\",\r\n title: input.title,\r\n total_amount: input.amount,\r\n trans_currency: \"ETB\",\r\n timeout_express: \"120m\",\r\n business_type: \"BuyGoods\",\r\n payee_type: \"3000\",\r\n payee_identifier: config.merchantCode,\r\n payee_identifier_type: \"04\",\r\n callback_info: \"From web\",\r\n },\r\n };\r\n\r\n reqBody.sign = signRequest(reqBody, config.privateKey);\r\n reqBody.sign_type = \"SHA256WithRSA\";\r\n\r\n const payload = JSON.stringify(reqBody);\r\n\r\n const baseUrl = TELEBIRR_URLS[config.mode].apiBase;\r\n const isHttps = baseUrl.startsWith(\"https://\");\r\n const client = isHttps ? https : http;\r\n\r\n return new Promise((resolve, reject) => {\r\n const req = client.request(\r\n `${baseUrl}/payment/v1/merchant/preOrder`,\r\n {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n \"Content-Length\": Buffer.byteLength(payload),\r\n \"X-APP-Key\": config.appId,\r\n Authorization: fabricToken,\r\n },\r\n ...(isHttps && { rejectUnauthorized: false }),\r\n },\r\n (res) => {\r\n let raw = \"\";\r\n\r\n res.on(\"data\", (chunk) => {\r\n raw += chunk;\r\n });\r\n\r\n res.on(\"end\", () => {\r\n const status = res.statusCode || 0;\r\n let parsed: any = raw;\r\n\r\n try {\r\n parsed = JSON.parse(raw);\r\n } catch {\r\n // keep raw string if JSON parsing fails\r\n }\r\n\r\n if (status < 200 || status >= 300) {\r\n return reject({\r\n message: \"Telebirr preorder request failed\",\r\n status,\r\n data: parsed,\r\n headers: res.headers,\r\n });\r\n }\r\n\r\n resolve({\r\n data: parsed,\r\n status,\r\n headers: res.headers,\r\n });\r\n });\r\n }\r\n );\r\n\r\n req.on(\"error\", (err) => {\r\n reject({\r\n message: \"Telebirr preorder network error\",\r\n cause: err,\r\n code: (err as any).code,\r\n });\r\n });\r\n\r\n req.write(payload);\r\n req.end();\r\n });\r\n}\r\n","import { randomBytes } from \"crypto\";\r\n\r\nexport function createNonceStr(): string {\r\n const bytes = Math.ceil(16);\r\n return randomBytes(bytes).toString(\"hex\").slice(0, 32);\r\n}\r\n","export function createTimestamp(): string {\r\n return Math.floor(Date.now() / 1000).toString();\r\n}\r\n","import crypto from \"crypto\";\r\n\r\nfunction flattenParams(params: Record<string, any>): Record<string, string> {\r\n const flat: Record<string, string> = {};\r\n\r\n for (const key in params) {\r\n const value = params[key];\r\n\r\n if (\r\n value === undefined ||\r\n value === null ||\r\n value === \"\" ||\r\n key === \"sign\" ||\r\n key === \"signType\" ||\r\n key === \"sign_type\"\r\n ) {\r\n continue;\r\n }\r\n\r\n if (key === \"biz_content\" && typeof value === \"object\") {\r\n for (const bizKey in value) {\r\n const bizValue = value[bizKey];\r\n if (bizValue !== undefined && bizValue !== null && bizValue !== \"\") {\r\n flat[bizKey] = String(bizValue);\r\n }\r\n }\r\n } else {\r\n flat[key] = String(value);\r\n }\r\n }\r\n\r\n return flat;\r\n}\r\n\r\nexport function buildSignString(params: Record<string, any>): string {\r\n const flat = flattenParams(params);\r\n\r\n return Object.keys(flat)\r\n .sort()\r\n .map((key) => `${key}=${flat[key]}`)\r\n .join(\"&\");\r\n}\r\n\r\nexport function signRequest(\r\n data: Record<string, any>,\r\n privateKey: string\r\n): string {\r\n const signString = buildSignString(data);\r\n\r\n return crypto\r\n .createSign(\"RSA-SHA256\")\r\n .update(signString, \"utf8\")\r\n .sign(privateKey, \"base64\");\r\n}\r\n","import http from \"http\";\r\nimport https from \"https\";\r\nimport { createNonceStr } from \"../utils/nonce\";\r\nimport { createTimestamp } from \"../utils/timestamp\";\r\nimport { signRequest } from \"../utils/signature\";\r\nimport { TelebirrMode } from \"../types/telebirrConfig\";\r\nimport {\r\n RefundInput,\r\n RefundResponse,\r\n TelebirrRefundRequest,\r\n} from \"../types/refund\";\r\nimport { TELEBIRR_URLS } from \"../constants/urls\";\r\n\r\nexport function requestRefund(\r\n fabricToken: string,\r\n input: RefundInput,\r\n config: {\r\n mode: TelebirrMode;\r\n appId: string;\r\n merchantAppId: string;\r\n merchantCode: string;\r\n privateKey: string;\r\n http: boolean;\r\n }\r\n): Promise<{\r\n data: RefundResponse;\r\n status: number;\r\n headers: http.IncomingHttpHeaders;\r\n}> {\r\n const reqBody: TelebirrRefundRequest = {\r\n timestamp: createTimestamp(),\r\n nonce_str: createNonceStr(),\r\n method: \"payment.refund\",\r\n version: \"1.0\",\r\n biz_content: {\r\n appid: config.merchantAppId,\r\n merch_code: config.merchantCode,\r\n merch_order_id: input.merchOrderId,\r\n trans_currency: \"ETB\",\r\n actual_amount: input.amount,\r\n refund_request_no: input.refundRequestNo,\r\n refund_reason: input.refundReason,\r\n },\r\n };\r\n\r\n reqBody.sign = signRequest(reqBody, config.privateKey);\r\n reqBody.sign_type = \"SHA256WithRSA\";\r\n\r\n const payload = JSON.stringify(reqBody);\r\n\r\n const baseUrl = TELEBIRR_URLS[config.mode].apiBase;\r\n const isHttps = baseUrl.startsWith(\"https://\");\r\n const client = isHttps ? https : http;\r\n\r\n return new Promise((resolve, reject) => {\r\n const req = client.request(\r\n `${baseUrl}/payment/v1/merchant/refund`,\r\n {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n \"Content-Length\": Buffer.byteLength(payload),\r\n \"X-APP-Key\": config.appId,\r\n Authorization: fabricToken,\r\n },\r\n ...(isHttps && { rejectUnauthorized: false }),\r\n },\r\n (res) => {\r\n let raw = \"\";\r\n\r\n res.on(\"data\", (chunk) => {\r\n raw += chunk;\r\n });\r\n\r\n res.on(\"end\", () => {\r\n const status = res.statusCode || 0;\r\n let parsed: any = raw;\r\n\r\n try {\r\n parsed = JSON.parse(raw);\r\n } catch {\r\n // keep raw string if JSON parsing fails\r\n }\r\n\r\n if (status < 200 || status >= 300) {\r\n return reject({\r\n message: \"Telebirr refund request failed\",\r\n status,\r\n data: parsed,\r\n headers: res.headers,\r\n });\r\n }\r\n\r\n resolve({\r\n data: parsed,\r\n status,\r\n headers: res.headers,\r\n });\r\n });\r\n }\r\n );\r\n\r\n req.on(\"error\", (err) => {\r\n reject({\r\n message: \"Telebirr refund network error\",\r\n cause: err,\r\n code: (err as any).code,\r\n });\r\n });\r\n\r\n req.write(payload);\r\n req.end();\r\n });\r\n}\r\n","import http from \"http\";\r\nimport https from \"https\";\r\nimport {\r\n TelebirrQueryorderRequest,\r\n QueryOrderResponse,\r\n} from \"../types/queryOrder\";\r\nimport { createNonceStr } from \"../utils/nonce\";\r\nimport { createTimestamp } from \"../utils/timestamp\";\r\nimport { signRequest } from \"../utils/signature\";\r\nimport { TelebirrMode } from \"../types/telebirrConfig\";\r\nimport { TELEBIRR_URLS } from \"../constants/urls\";\r\n\r\nexport function requestQueryOrder(\r\n fabricToken: string,\r\n merchOrderId: string,\r\n config: {\r\n appId: string;\r\n appSecret: string;\r\n merchantAppId: string;\r\n merchantCode: string;\r\n privateKey: string;\r\n notifyUrl: string;\r\n redirectUrl: string;\r\n mode: TelebirrMode;\r\n http: boolean;\r\n }\r\n): Promise<{\r\n data: QueryOrderResponse;\r\n status: number;\r\n headers: http.IncomingHttpHeaders;\r\n}> {\r\n const reqBody: TelebirrQueryorderRequest = {\r\n timestamp: createTimestamp(),\r\n nonce_str: createNonceStr(),\r\n method: \"payment.queryorder\",\r\n version: \"1.0\",\r\n biz_content: {\r\n appid: config.merchantAppId,\r\n merch_code: config.merchantCode,\r\n merch_order_id: merchOrderId,\r\n },\r\n };\r\n\r\n reqBody.sign = signRequest(reqBody, config.privateKey);\r\n reqBody.sign_type = \"SHA256WithRSA\";\r\n\r\n const payload = JSON.stringify(reqBody);\r\n\r\n const baseUrl = TELEBIRR_URLS[config.mode].apiBase;\r\n const isHttps = baseUrl.startsWith(\"https://\");\r\n const client = isHttps ? https : http;\r\n\r\n return new Promise((resolve, reject) => {\r\n const req = client.request(\r\n `${baseUrl}/payment/v1/merchant/queryOrder`,\r\n {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n \"Content-Length\": Buffer.byteLength(payload),\r\n \"X-APP-Key\": config.appId,\r\n Authorization: fabricToken,\r\n },\r\n ...(isHttps && { rejectUnauthorized: false }),\r\n },\r\n (res) => {\r\n let raw = \"\";\r\n\r\n res.on(\"data\", (chunk) => {\r\n raw += chunk;\r\n });\r\n\r\n res.on(\"end\", () => {\r\n const status = res.statusCode || 0;\r\n let parsed: any = raw;\r\n\r\n try {\r\n parsed = JSON.parse(raw);\r\n } catch {\r\n // keep raw if parsing fails\r\n }\r\n\r\n if (status < 200 || status >= 300) {\r\n return reject({\r\n message: \"Telebirr queryOrder request failed\",\r\n status,\r\n data: parsed,\r\n headers: res.headers,\r\n });\r\n }\r\n\r\n resolve({\r\n data: parsed,\r\n status,\r\n headers: res.headers,\r\n });\r\n });\r\n }\r\n );\r\n\r\n req.on(\"error\", (err) => {\r\n reject({\r\n message: \"Telebirr queryOrder network error\",\r\n cause: err,\r\n code: (err as any).code,\r\n });\r\n });\r\n\r\n req.write(payload);\r\n req.end();\r\n });\r\n}\r\n","import { TelebirrConfig } from \"../types/telebirrConfig\";\r\nimport { FabricTokenResponse } from \"../types/fabricToken\";\r\nimport { GenerateCheckoutUrlInput } from \"../types/createOrder\";\r\nimport { generateCredentials } from \"../utils/credentials\";\r\nimport { QueryOrderResponse } from \"../types/queryOrder\";\r\nimport { RefundInput, RefundResponse } from \"../types/refund\";\r\nimport { requestToken } from \"../services/requestToken\";\r\nimport { requestCreateOrder } from \"../services/requestCreateOrder\";\r\nimport { requestRefund } from \"../services/requestRefundOrder\";\r\nimport { requestQueryOrder } from \"../services/requestQueryOrder\";\r\nimport { TELEBIRR_URLS, CHECKOUT_OTHER_PARAMS } from \"../constants/urls\";\r\nimport { signRequest } from \"../utils/signature\";\r\nimport { createTimestamp } from \"../utils/timestamp\";\r\nimport { createNonceStr } from \"../utils/nonce\";\r\n\r\nexport class C2B {\r\n private token?: typeof FabricTokenResponse;\r\n private config: TelebirrConfig;\r\n\r\n constructor(config: TelebirrConfig) {\r\n if (config.mode === \"simulate\") {\r\n generateCredentials();\r\n this.config = config;\r\n } else {\r\n this.config = config;\r\n }\r\n }\r\n\r\n async getFabricToken(): Promise<any> {\r\n if (this.token && !this.isTokenExpired(this.token)) {\r\n return this.token;\r\n }\r\n\r\n let token: any = await requestToken(this.config);\r\n token = JSON.parse(token);\r\n if (!token) return;\r\n this.token = token;\r\n return token;\r\n }\r\n\r\n private createCheckoutUrl(prepayId: string): string {\r\n const map = {\r\n appid: this.config.merchantAppId,\r\n merch_code: this.config.merchantCode,\r\n nonce_str: createNonceStr(),\r\n prepay_id: prepayId,\r\n timestamp: createTimestamp(),\r\n };\r\n\r\n const sign = signRequest(map, this.config.privateKey);\r\n\r\n const rawRequest = [\r\n `appid=${map.appid}`,\r\n `merch_code=${map.merch_code}`,\r\n `nonce_str=${map.nonce_str}`,\r\n `prepay_id=${map.prepay_id}`,\r\n `timestamp=${map.timestamp}`,\r\n `sign=${sign}`,\r\n `sign_type=SHA256WithRSA`,\r\n ].join(\"&\");\r\n\r\n const webBase = TELEBIRR_URLS[this.config.mode].webBase;\r\n\r\n return webBase + rawRequest + CHECKOUT_OTHER_PARAMS;\r\n }\r\n async preOrder(input: GenerateCheckoutUrlInput): Promise<string | void> {\r\n const token = await this.getFabricToken();\r\n\r\n if (!token) return;\r\n\r\n let response: any = await requestCreateOrder(\r\n token.token,\r\n input,\r\n this.config\r\n );\r\n if (!response) return;\r\n\r\n return this.createCheckoutUrl(response.data.biz_content.prepay_id);\r\n }\r\n\r\n async queryOrder(input: string): Promise<QueryOrderResponse | void> {\r\n let token = await this.getFabricToken();\r\n\r\n if (!token) return;\r\n\r\n const response: any = await requestQueryOrder(\r\n token.token,\r\n input,\r\n this.config\r\n );\r\n\r\n return response.data;\r\n }\r\n async refundOrder(input: RefundInput): Promise<RefundResponse | void> {\r\n const token = await this.getFabricToken();\r\n if (!token) return;\r\n const response: any = await requestRefund(token.token, input, this.config);\r\n\r\n return response.data;\r\n }\r\n\r\n private static readonly TOKEN_EXPIRY_SAFETY_WINDOW_MS = 5 * 60 * 1000;\r\n\r\n private isTokenExpired(token?: typeof FabricTokenResponse): boolean {\r\n if (!token) {\r\n return true;\r\n }\r\n\r\n const now = Date.now();\r\n const expiry = this.parseTelebirrDate(token.expirationDate).getTime();\r\n\r\n return now >= expiry - C2B.TOKEN_EXPIRY_SAFETY_WINDOW_MS;\r\n }\r\n\r\n private parseTelebirrDate(value: string): Date {\r\n const year = Number(value.slice(0, 4));\r\n const month = Number(value.slice(4, 6)) - 1;\r\n const day = Number(value.slice(6, 8));\r\n const hour = Number(value.slice(8, 10));\r\n const minute = Number(value.slice(10, 12));\r\n const second = Number(value.slice(12, 14));\r\n\r\n return new Date(Date.UTC(year, month, day, hour, minute, second));\r\n }\r\n}\r\n"],"mappings":"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","names":["fs","path","path","fs","http","https","randomBytes","https","http","http","https","https","http","http","https","https","http"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "telebirr-nodejs",
|
|
3
|
-
"version": "1.0
|
|
4
|
-
"description": "Unofficial
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Unofficial Node.js SDK for Telebirr C2B payments with automatic request signing, Fabric token handling, checkout URL generation, simulator support, and simplified refunds & payment status APIs.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
7
7
|
"module": "./dist/index.js",
|
|
@@ -30,8 +30,20 @@
|
|
|
30
30
|
"ethiopia",
|
|
31
31
|
"payment",
|
|
32
32
|
"fintech",
|
|
33
|
-
"nodejs"
|
|
33
|
+
"nodejs",
|
|
34
|
+
"telebirr-node",
|
|
35
|
+
"telebirr-nodejs",
|
|
36
|
+
"telebirr-payment",
|
|
37
|
+
"ethiopia-payment",
|
|
38
|
+
"c2b-payment",
|
|
39
|
+
"b2b-payment",
|
|
40
|
+
"nodejs-payment",
|
|
41
|
+
"payment-gateway"
|
|
34
42
|
],
|
|
35
|
-
"author": "
|
|
36
|
-
"license": "MIT"
|
|
43
|
+
"author": "Chernet Manaye (https://github.com/chernetManaye)",
|
|
44
|
+
"license": "MIT",
|
|
45
|
+
"homepage": "https://github.com/chernetManaye/telebirr-nodejs",
|
|
46
|
+
"bugs": {
|
|
47
|
+
"url": "https://github.com/chernetManaye/telebirr-nodejs/issues"
|
|
48
|
+
}
|
|
37
49
|
}
|