@nile-squad/nylonpay-ts 1.2.0 → 1.3.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/README.md +7 -10
- package/dist/index.cjs +58 -29
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +97 -1
- package/dist/index.d.ts +97 -1
- package/dist/index.js +59 -30
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -41,7 +41,7 @@ Use your test keys to work in sandbox, or your production keys to go live. There
|
|
|
41
41
|
|---|---|---|---|
|
|
42
42
|
| `apiKey` | Yes | | Must start with `npk_` |
|
|
43
43
|
| `apiSecret` | Yes | | Must start with `nps_` |
|
|
44
|
-
| `baseUrl` | No | Default is used | Override
|
|
44
|
+
| `baseUrl` | No | Default is used | Override for a custom endpoint |
|
|
45
45
|
| `timeoutMs` | No | `30000` | Request timeout in milliseconds |
|
|
46
46
|
| `maxRetries` | No | `3` | Retry count for failed requests |
|
|
47
47
|
| `maxPollIntervalMs` | No | `2000` | Polling interval for async payments |
|
|
@@ -231,16 +231,13 @@ if (!result.isOk) {
|
|
|
231
231
|
|
|
232
232
|
`USD`, `EUR`, `GBP`, `KES`, `UGX`, `TZS`, `RWF`
|
|
233
233
|
|
|
234
|
-
##
|
|
234
|
+
## Links
|
|
235
235
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
pnpm typecheck # tsc --noEmit
|
|
242
|
-
pnpm build # tsup
|
|
243
|
-
```
|
|
236
|
+
- [Documentation](https://docs.nylonpay.nilesquad.com/docs)
|
|
237
|
+
- [SDK Spec](https://github.com/nile-squad/specs/blob/main/nylonpay-sdk-spec/spec.md)
|
|
238
|
+
- [GitHub Repository](https://github.com/nile-squad/nylonpay-ts)
|
|
239
|
+
- [Python SDK](https://github.com/nile-squad/nylonpay-py)
|
|
240
|
+
- [Nylon Pay](https://nylonpay.nilesquad.com)
|
|
244
241
|
|
|
245
242
|
## License
|
|
246
243
|
|
package/dist/index.cjs
CHANGED
|
@@ -72,10 +72,12 @@ var SDK_ACTIONS = {
|
|
|
72
72
|
makePayoutAndResolve: "sdk-make-payout-and-resolve",
|
|
73
73
|
getStatus: "sdk-get-status",
|
|
74
74
|
getTransaction: "sdk-get-transaction",
|
|
75
|
+
listTransactions: "sdk-list-transactions",
|
|
75
76
|
verifyPhone: "sdk-verify-phone",
|
|
76
77
|
createInvoice: "sdk-create-invoice"
|
|
77
78
|
};
|
|
78
79
|
var RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([408, 429, 500, 502, 503, 504]);
|
|
80
|
+
var MAX_RESPONSE_BYTES = 10 * 1024 * 1024;
|
|
79
81
|
function generateFingerprint() {
|
|
80
82
|
const components = [
|
|
81
83
|
`type:${os.type()}`,
|
|
@@ -270,6 +272,17 @@ function createTransport({
|
|
|
270
272
|
body: bodyString,
|
|
271
273
|
signal: controller.signal
|
|
272
274
|
});
|
|
275
|
+
const contentLength = response.headers?.get("content-length");
|
|
276
|
+
if (contentLength && Number(contentLength) > MAX_RESPONSE_BYTES) {
|
|
277
|
+
cleanup();
|
|
278
|
+
return slangTs.Err(
|
|
279
|
+
JSON.stringify({
|
|
280
|
+
category: "internal",
|
|
281
|
+
message: "Received an invalid response from the server",
|
|
282
|
+
retryable: false
|
|
283
|
+
})
|
|
284
|
+
);
|
|
285
|
+
}
|
|
273
286
|
if (!response.ok) {
|
|
274
287
|
const statusCode = response.status;
|
|
275
288
|
const retryable = RETRYABLE_STATUS_CODES.has(statusCode);
|
|
@@ -657,43 +670,44 @@ function extractSignedTimestampMs(payloadString) {
|
|
|
657
670
|
return null;
|
|
658
671
|
}
|
|
659
672
|
function verifyWebhookSignature(input) {
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
673
|
+
try {
|
|
674
|
+
const payloadString = decodePayload(input.payload);
|
|
675
|
+
const payloadBytes = Buffer.from(payloadString, "utf8");
|
|
676
|
+
const expectedSignature = crypto.createHmac("sha256", input.secret).update(payloadBytes).digest("hex");
|
|
677
|
+
const providedBuffer = Buffer.from(input.signature, "hex");
|
|
678
|
+
const expectedBuffer = Buffer.from(expectedSignature, "hex");
|
|
679
|
+
if (providedBuffer.length !== expectedBuffer.length) {
|
|
680
|
+
return false;
|
|
681
|
+
}
|
|
682
|
+
if (!crypto.timingSafeEqual(providedBuffer, expectedBuffer)) {
|
|
683
|
+
return false;
|
|
684
|
+
}
|
|
685
|
+
const toleranceSeconds = input.toleranceSeconds ?? DEFAULT_TOLERANCE_SECONDS;
|
|
686
|
+
if (toleranceSeconds === 0) {
|
|
687
|
+
return true;
|
|
688
|
+
}
|
|
689
|
+
if (toleranceSeconds < 0) {
|
|
690
|
+
return false;
|
|
691
|
+
}
|
|
692
|
+
const timestampMs = extractSignedTimestampMs(payloadString);
|
|
693
|
+
if (timestampMs === null) {
|
|
694
|
+
return false;
|
|
695
|
+
}
|
|
696
|
+
const ageMs = Math.abs(Date.now() - timestampMs);
|
|
697
|
+
return ageMs <= toleranceSeconds * 1e3;
|
|
698
|
+
} catch {
|
|
677
699
|
return false;
|
|
678
700
|
}
|
|
679
|
-
const ageMs = Math.abs(Date.now() - timestampMs);
|
|
680
|
-
return ageMs <= toleranceSeconds * 1e3;
|
|
681
701
|
}
|
|
682
702
|
|
|
683
703
|
// src/sdk.ts
|
|
684
|
-
|
|
685
|
-
return crypto.randomBytes(16).toString("hex").slice(0, 15);
|
|
686
|
-
}
|
|
687
|
-
var REFERENCE_MIN_LENGTH = 13;
|
|
688
|
-
var REFERENCE_MAX_LENGTH = 15;
|
|
704
|
+
var UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
689
705
|
function resolveReference(reference) {
|
|
690
706
|
if (reference === void 0) {
|
|
691
|
-
return
|
|
707
|
+
return crypto.randomUUID();
|
|
692
708
|
}
|
|
693
|
-
if (
|
|
694
|
-
throwValidation(
|
|
695
|
-
`reference must be ${REFERENCE_MIN_LENGTH}\u2013${REFERENCE_MAX_LENGTH} characters`
|
|
696
|
-
);
|
|
709
|
+
if (!UUID_REGEX.test(reference)) {
|
|
710
|
+
throwValidation("reference must be a valid UUID");
|
|
697
711
|
}
|
|
698
712
|
return reference;
|
|
699
713
|
}
|
|
@@ -960,6 +974,19 @@ function createSdkInstance(config) {
|
|
|
960
974
|
}
|
|
961
975
|
return slangTs.Err(result.error);
|
|
962
976
|
}
|
|
977
|
+
async function listTransactions(input) {
|
|
978
|
+
const result = await transport.send({
|
|
979
|
+
action: SDK_ACTIONS.listTransactions,
|
|
980
|
+
payload: input ?? {}
|
|
981
|
+
});
|
|
982
|
+
if (result.isOk) {
|
|
983
|
+
return slangTs.Ok(result.value);
|
|
984
|
+
}
|
|
985
|
+
return slangTs.Err(result.error);
|
|
986
|
+
}
|
|
987
|
+
async function getTransactionsByTag(tag, options) {
|
|
988
|
+
return listTransactions({ ...options, tags: [tag] });
|
|
989
|
+
}
|
|
963
990
|
function verifyWebhook(input) {
|
|
964
991
|
return verifyWebhookSignature(input);
|
|
965
992
|
}
|
|
@@ -970,6 +997,8 @@ function createSdkInstance(config) {
|
|
|
970
997
|
makePayoutAndResolve,
|
|
971
998
|
getStatus,
|
|
972
999
|
getTransaction,
|
|
1000
|
+
listTransactions,
|
|
1001
|
+
getTransactionsByTag,
|
|
973
1002
|
verifyPhone,
|
|
974
1003
|
createInvoice,
|
|
975
1004
|
verifyWebhookSignature: verifyWebhook
|