@yosle/tropipayjs 0.1.22 → 0.1.23

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.
@@ -1,79 +1,79 @@
1
- import { Tropipay } from "../../src/api/TropipayAPI";
2
- import { PaymentLinkPayload } from "../interfaces";
3
- import { TropipayJSException } from "../utils/errors";
4
- import PaymentCard from "./PaymentCard";
5
-
6
- jest.mock("axios");
7
- jest.mock("../../src/api/TropipayAPI");
8
-
9
- describe("Create PaymentCard", () => {
10
- describe("create", () => {
11
- it("should create a payment link", async () => {
12
- const payload: PaymentLinkPayload = {
13
- amount: 200,
14
- client: null,
15
- concept: "Concept",
16
- currency: "EUR",
17
- description: "Description",
18
- directPayment: true,
19
- expirationDays: 30,
20
- favorite: false,
21
- reasonId: 45,
22
- reference: "Reference",
23
- serviceDate: "2022-01-01",
24
- urlFailed: "urlFailed",
25
- urlNotification: "urlNotification",
26
- urlSuccess: "urlSuccess",
27
- singleUse: false,
28
- paymentMethods: ["EXT"],
29
- lang: "es",
30
- };
31
- const expectedPaymentLink = {
32
- id: "1f8b0600-0b62-11ef-b879-9d16dab40e58",
33
- reference: "08025834659",
34
- concept: "NFT Purchase",
35
- description: "Golden Monkey NFT character",
36
- amount: 500,
37
- currency: "EUR",
38
- singleUse: true,
39
- favorite: false,
40
- reasonId: 4,
41
- reasonDes: null,
42
- expirationDays: 0,
43
- userId: "a9546500-65c0-11ed-97e6-2ffd2c53074d",
44
- lang: "es",
45
- imageBase: null,
46
- state: 1,
47
- urlSuccess: null,
48
- urlFailed: null,
49
- urlNotification: null,
50
- expirationDate: null,
51
- serviceDate: null,
52
- hasClient: false,
53
- credentialId: 129710,
54
- force3ds: false,
55
- saveToken: true,
56
- origin: 2,
57
- paymentcardType: 1,
58
- updatedAt: "2024-05-06T04:35:54.352Z",
59
- createdAt: "2024-05-06T04:35:53.568Z",
60
- qrImage:
61
- "data:image/png;base64,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",
62
- shortUrl: "https://tppay.me/lvugy80i",
63
- paymentUrl: null,
64
- rawUrlPayment: null,
65
- giftcard: null,
66
- };
67
-
68
- const tropipayInstance = new Tropipay({
69
- clientId: "clientId",
70
- clientSecret: "clientSecret",
71
- });
72
-
73
- const result = await tropipayInstance.paymentCards.create(payload);
74
-
75
- // expect(result).toEqual(expectedPaymentLink);
76
- expect(true).toBeDefined();
77
- });
78
- });
79
- });
1
+ import { Tropipay } from "../../src/api/TropipayAPI";
2
+ import { PaymentLinkPayload } from "../interfaces";
3
+ import { TropipayJSException } from "../utils/errors";
4
+ import PaymentCard from "./PaymentCard";
5
+
6
+ jest.mock("axios");
7
+ jest.mock("../../src/api/TropipayAPI");
8
+
9
+ describe("Create PaymentCard", () => {
10
+ describe("create", () => {
11
+ it("should create a payment link", async () => {
12
+ const payload: PaymentLinkPayload = {
13
+ amount: 200,
14
+ client: null,
15
+ concept: "Concept",
16
+ currency: "EUR",
17
+ description: "Description",
18
+ directPayment: true,
19
+ expirationDays: 30,
20
+ favorite: false,
21
+ reasonId: 45,
22
+ reference: "Reference",
23
+ serviceDate: "2022-01-01",
24
+ urlFailed: "urlFailed",
25
+ urlNotification: "urlNotification",
26
+ urlSuccess: "urlSuccess",
27
+ singleUse: false,
28
+ paymentMethods: ["EXT"],
29
+ lang: "es",
30
+ };
31
+ const expectedPaymentLink = {
32
+ id: "1f8b0600-0b62-11ef-b879-9d16dab40e58",
33
+ reference: "08025834659",
34
+ concept: "NFT Purchase",
35
+ description: "Golden Monkey NFT character",
36
+ amount: 500,
37
+ currency: "EUR",
38
+ singleUse: true,
39
+ favorite: false,
40
+ reasonId: 4,
41
+ reasonDes: null,
42
+ expirationDays: 0,
43
+ userId: "a9546500-65c0-11ed-97e6-2ffd2c53074d",
44
+ lang: "es",
45
+ imageBase: null,
46
+ state: 1,
47
+ urlSuccess: null,
48
+ urlFailed: null,
49
+ urlNotification: null,
50
+ expirationDate: null,
51
+ serviceDate: null,
52
+ hasClient: false,
53
+ credentialId: 129710,
54
+ force3ds: false,
55
+ saveToken: true,
56
+ origin: 2,
57
+ paymentcardType: 1,
58
+ updatedAt: "2024-05-06T04:35:54.352Z",
59
+ createdAt: "2024-05-06T04:35:53.568Z",
60
+ qrImage:
61
+ "data:image/png;base64,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",
62
+ shortUrl: "https://tppay.me/lvugy80i",
63
+ paymentUrl: null,
64
+ rawUrlPayment: null,
65
+ giftcard: null,
66
+ };
67
+
68
+ const tropipayInstance = new Tropipay({
69
+ clientId: "clientId",
70
+ clientSecret: "clientSecret",
71
+ });
72
+
73
+ const result = await tropipayInstance.paymentCards.create(payload);
74
+
75
+ // expect(result).toEqual(expectedPaymentLink);
76
+ expect(true).toBeDefined();
77
+ });
78
+ });
79
+ });
@@ -1,126 +1,126 @@
1
- import * as crypto from "crypto";
2
- import { Tropipay } from "../api/TropipayAPI";
3
-
4
- import axios from "axios";
5
- import fs from "fs/promises";
6
- import { MAX_IMAGE_SIZE_MB } from "../constants/TropipayConstants";
7
- export class ServerSideUtils {
8
- private tropipay: Tropipay;
9
- constructor(tropipayInstance: Tropipay) {
10
- this.tropipay = tropipayInstance;
11
- }
12
-
13
- /**
14
- * Verify Topipay's signature on webhooks.
15
- * @param credentials Credential object or Tropipay instance
16
- * @param {String} originalCurrencyAmount
17
- * @param bankOrderCode
18
- * @param signature
19
- * @returns {Boolean}
20
- */
21
- public static verifySignature(
22
- credentials:
23
- | {
24
- clientId: string;
25
- clientSecret: string;
26
- }
27
- | Tropipay,
28
- originalCurrencyAmount: string,
29
- bankOrderCode: string,
30
- signature: string
31
- ): boolean {
32
- const localSignature = crypto
33
- .createHash("sha256")
34
- .update(
35
- bankOrderCode +
36
- credentials.clientId +
37
- credentials.clientSecret +
38
- originalCurrencyAmount
39
- )
40
- .digest("hex");
41
- return localSignature === signature;
42
- }
43
- /**
44
- * Checks if the provided base64 string represents a square image.
45
- *
46
- * @param {string} base64String - The base64 string of the image
47
- * @return {Promise<boolean>} A Promise that resolves to a boolean indicating whether the image is square
48
- */
49
- public static async isBase64ImageSquare(
50
- base64String: string
51
- ): Promise<boolean> {
52
- return new Promise<boolean>((resolve, reject) => {
53
- const img = new Image();
54
-
55
- img.onload = () => {
56
- // Check if the image has a 1:1 aspect ratio
57
- const isSquare = img.width === img.height;
58
- resolve(isSquare);
59
- };
60
-
61
- img.onerror = (error) => {
62
- reject(error);
63
- };
64
-
65
- img.src = base64String;
66
- });
67
- }
68
-
69
- /**
70
- * Takes a local file path and returns a base64 representation of the file content.
71
- *
72
- * @param {string} filepath - the path of the file to be converted to base64
73
- * @return {Promise<string>} a Promise that resolves to the base64 representation of the file content
74
- */
75
- public static async fileToBase64(filepath: string): Promise<string> {
76
- const contents = await fs.readFile(filepath);
77
- let base64content = contents.toString("base64");
78
- const ext = filepath.split(".").pop();
79
- return `data:image/${ext};base64,` + base64content;
80
- }
81
-
82
- /**
83
- * Get the base64 representation of a remote file from the given URL.
84
- *
85
- * @param {string} url - the URL of the file
86
- * @return {Promise<string>} the base64 representation of the file
87
- */
88
- public static async getBase64FromFileUrl(url: string): Promise<string> {
89
- const response = await axios.get(url, {
90
- responseType: "arraybuffer",
91
- maxRedirects: 5,
92
- });
93
- return Buffer.from(response.data, "binary").toString("base64");
94
- }
95
-
96
- /**
97
- * Check if the base64 string represents a valid image and has a valid size
98
- *
99
- * @param {string} base64Image - the base64 image to be validated
100
- * @return {Promise<string>} the valid base64 image
101
- */
102
- public static isValidImage(base64Image: string): boolean {
103
- // Check if the base64 string represents a valid image and has a valid size
104
- try {
105
- const isBase64Image = base64Image.startsWith("data:image/");
106
- if (!isBase64Image) {
107
- console.error("Not a valid base64 image");
108
- throw new Error("Not a valid base64 image");
109
- }
110
-
111
- // TODO: use constants intead of magic numbers here
112
- const isSizeLessThan2MB =
113
- base64Image.length * 0.75 <= MAX_IMAGE_SIZE_MB * 1024 * 1024;
114
-
115
- if (!isSizeLessThan2MB) {
116
- console.error(`The image should be less than 2mb`);
117
- throw new Error(`The image should be less than 2mb`);
118
- }
119
- // all is fine
120
- return true;
121
- } catch (error) {
122
- console.error("Error checking base64 image:", error);
123
- throw new Error(`Error checking base64 image`);
124
- }
125
- }
126
- }
1
+ import * as crypto from "crypto";
2
+ import { Tropipay } from "../api/TropipayAPI";
3
+
4
+ import axios from "axios";
5
+ import fs from "fs/promises";
6
+ import { MAX_IMAGE_SIZE_MB } from "../constants/TropipayConstants";
7
+ export class ServerSideUtils {
8
+ private tropipay: Tropipay;
9
+ constructor(tropipayInstance: Tropipay) {
10
+ this.tropipay = tropipayInstance;
11
+ }
12
+
13
+ /**
14
+ * Verify Topipay's signature on webhooks.
15
+ * @param credentials Credential object or Tropipay instance
16
+ * @param {String} originalCurrencyAmount
17
+ * @param bankOrderCode
18
+ * @param signature
19
+ * @returns {Boolean}
20
+ */
21
+ public static verifySignature(
22
+ credentials:
23
+ | {
24
+ clientId: string;
25
+ clientSecret: string;
26
+ }
27
+ | Tropipay,
28
+ originalCurrencyAmount: string,
29
+ bankOrderCode: string,
30
+ signature: string
31
+ ): boolean {
32
+ const localSignature = crypto
33
+ .createHash("sha256")
34
+ .update(
35
+ bankOrderCode +
36
+ credentials.clientId +
37
+ credentials.clientSecret +
38
+ originalCurrencyAmount
39
+ )
40
+ .digest("hex");
41
+ return localSignature === signature;
42
+ }
43
+ /**
44
+ * Checks if the provided base64 string represents a square image.
45
+ *
46
+ * @param {string} base64String - The base64 string of the image
47
+ * @return {Promise<boolean>} A Promise that resolves to a boolean indicating whether the image is square
48
+ */
49
+ public static async isBase64ImageSquare(
50
+ base64String: string
51
+ ): Promise<boolean> {
52
+ return new Promise<boolean>((resolve, reject) => {
53
+ const img = new Image();
54
+
55
+ img.onload = () => {
56
+ // Check if the image has a 1:1 aspect ratio
57
+ const isSquare = img.width === img.height;
58
+ resolve(isSquare);
59
+ };
60
+
61
+ img.onerror = (error) => {
62
+ reject(error);
63
+ };
64
+
65
+ img.src = base64String;
66
+ });
67
+ }
68
+
69
+ /**
70
+ * Takes a local file path and returns a base64 representation of the file content.
71
+ *
72
+ * @param {string} filepath - the path of the file to be converted to base64
73
+ * @return {Promise<string>} a Promise that resolves to the base64 representation of the file content
74
+ */
75
+ public static async fileToBase64(filepath: string): Promise<string> {
76
+ const contents = await fs.readFile(filepath);
77
+ let base64content = contents.toString("base64");
78
+ const ext = filepath.split(".").pop();
79
+ return `data:image/${ext};base64,` + base64content;
80
+ }
81
+
82
+ /**
83
+ * Get the base64 representation of a remote file from the given URL.
84
+ *
85
+ * @param {string} url - the URL of the file
86
+ * @return {Promise<string>} the base64 representation of the file
87
+ */
88
+ public static async getBase64FromFileUrl(url: string): Promise<string> {
89
+ const response = await axios.get(url, {
90
+ responseType: "arraybuffer",
91
+ maxRedirects: 5,
92
+ });
93
+ return Buffer.from(response.data, "binary").toString("base64");
94
+ }
95
+
96
+ /**
97
+ * Check if the base64 string represents a valid image and has a valid size
98
+ *
99
+ * @param {string} base64Image - the base64 image to be validated
100
+ * @return {Promise<string>} the valid base64 image
101
+ */
102
+ public static isValidImage(base64Image: string): boolean {
103
+ // Check if the base64 string represents a valid image and has a valid size
104
+ try {
105
+ const isBase64Image = base64Image.startsWith("data:image/");
106
+ if (!isBase64Image) {
107
+ console.error("Not a valid base64 image");
108
+ throw new Error("Not a valid base64 image");
109
+ }
110
+
111
+ // TODO: use constants intead of magic numbers here
112
+ const isSizeLessThan2MB =
113
+ base64Image.length * 0.75 <= MAX_IMAGE_SIZE_MB * 1024 * 1024;
114
+
115
+ if (!isSizeLessThan2MB) {
116
+ console.error(`The image should be less than 2mb`);
117
+ throw new Error(`The image should be less than 2mb`);
118
+ }
119
+ // all is fine
120
+ return true;
121
+ } catch (error) {
122
+ console.error("Error checking base64 image:", error);
123
+ throw new Error(`Error checking base64 image`);
124
+ }
125
+ }
126
+ }
@@ -1,92 +1,92 @@
1
- import { AxiosError, AxiosResponse } from "axios";
2
-
3
- const ErrorType = {
4
- VALIDATION_ERROR: "VALIDATION_ERROR", // 400
5
- UNAUTHORIZED_ERROR: "UNAUTHORIZED_ERROR", // 401 (Not valid credentials)
6
- FORBIDDEN_ERROR: "FORBIDDEN_ERROR", // 403 (Valid credentials but insufficient to grant access)
7
- NOT_FOUND: "NOT_FOUND", // 404
8
- RATE_LIMIT_ERROR: "RATE_LIMIT_ERROR", // 429 (Used only in cloudflare for now)
9
- OPERATION_ERROR: "OPERATION_ERROR", // 500
10
- } as const;
11
-
12
- const ErrorCode = {
13
- VALIDATION_ERROR: "VALIDATION_ERROR",
14
- UNAUTHORIZED_ERROR: "UNAUTHORIZED_ERROR",
15
- FORBIDDEN_ERROR: "FORBIDDEN_ERROR",
16
- NOT_FOUND: "NOT_FOUND",
17
- RATE_LIMIT_ERROR: "RATE_LIMIT_ERROR",
18
- OPERATION_ERROR: "OPERATION_ERROR",
19
- SYNTAX_ERROR: "SYNTAX_ERROR",
20
- INVALID_PARAM: "INVALID_PARAM",
21
- UNHANDLED_ERROR: "SERVER_ERROR",
22
- } as const;
23
-
24
- export interface ErrorDetail {
25
- param: string;
26
- value: string | number | null;
27
- msg: string;
28
- code: string;
29
- location: string | null;
30
- meta: unknown;
31
- }
32
- export function handleExceptions(
33
- error: AxiosError | Error
34
- ): TropipayJSException {
35
- if (error instanceof AxiosError) {
36
- if (error.response) {
37
- const axiosResponse: AxiosResponse = error.response;
38
- const errorMessage =
39
- axiosResponse.data?.error?.message || "An error occurred";
40
-
41
- switch (axiosResponse.status) {
42
- case 400:
43
- case 401:
44
- case 403:
45
- case 404:
46
- return new TropipayJSException(
47
- errorMessage,
48
- axiosResponse.status,
49
- axiosResponse.data.error
50
- );
51
- case 429:
52
- return new TropipayJSException(
53
- `${errorMessage} Too many request or rate limited`,
54
- axiosResponse.status,
55
- axiosResponse.data.error
56
- );
57
- default:
58
- return new TropipayJSException(
59
- errorMessage,
60
- axiosResponse.status,
61
- axiosResponse.data.error
62
- );
63
- }
64
- } else if (error.request) {
65
- // Axios request was made but no response received (e.g., network error)
66
- return new TropipayJSException(
67
- "Request failed: No response received",
68
- 500,
69
- null
70
- );
71
- } else {
72
- // Something else went wrong
73
- return new TropipayJSException("An error occurred", 500, null);
74
- }
75
- } else {
76
- return new TropipayJSException("An Unknown error occurred", 500, null);
77
- }
78
- }
79
-
80
- export class TropipayJSException extends Error {
81
- code: number; // Status code
82
- error: unknown;
83
- message: string;
84
- constructor(message: string, code: number, data: unknown) {
85
- super(message);
86
- // Set the prototype explicitly.
87
- Object.setPrototypeOf(this, TropipayJSException.prototype);
88
- this.code = code;
89
- this.error = data;
90
- this.message = message;
91
- }
92
- }
1
+ import { AxiosError, AxiosResponse } from "axios";
2
+
3
+ const ErrorType = {
4
+ VALIDATION_ERROR: "VALIDATION_ERROR", // 400
5
+ UNAUTHORIZED_ERROR: "UNAUTHORIZED_ERROR", // 401 (Not valid credentials)
6
+ FORBIDDEN_ERROR: "FORBIDDEN_ERROR", // 403 (Valid credentials but insufficient to grant access)
7
+ NOT_FOUND: "NOT_FOUND", // 404
8
+ RATE_LIMIT_ERROR: "RATE_LIMIT_ERROR", // 429 (Used only in cloudflare for now)
9
+ OPERATION_ERROR: "OPERATION_ERROR", // 500
10
+ } as const;
11
+
12
+ const ErrorCode = {
13
+ VALIDATION_ERROR: "VALIDATION_ERROR",
14
+ UNAUTHORIZED_ERROR: "UNAUTHORIZED_ERROR",
15
+ FORBIDDEN_ERROR: "FORBIDDEN_ERROR",
16
+ NOT_FOUND: "NOT_FOUND",
17
+ RATE_LIMIT_ERROR: "RATE_LIMIT_ERROR",
18
+ OPERATION_ERROR: "OPERATION_ERROR",
19
+ SYNTAX_ERROR: "SYNTAX_ERROR",
20
+ INVALID_PARAM: "INVALID_PARAM",
21
+ UNHANDLED_ERROR: "SERVER_ERROR",
22
+ } as const;
23
+
24
+ export interface ErrorDetail {
25
+ param: string;
26
+ value: string | number | null;
27
+ msg: string;
28
+ code: string;
29
+ location: string | null;
30
+ meta: unknown;
31
+ }
32
+ export function handleExceptions(
33
+ error: AxiosError | Error
34
+ ): TropipayJSException {
35
+ if (error instanceof AxiosError) {
36
+ if (error.response) {
37
+ const axiosResponse: AxiosResponse = error.response;
38
+ const errorMessage =
39
+ axiosResponse.data?.error?.message || "An error occurred";
40
+
41
+ switch (axiosResponse.status) {
42
+ case 400:
43
+ case 401:
44
+ case 403:
45
+ case 404:
46
+ return new TropipayJSException(
47
+ errorMessage,
48
+ axiosResponse.status,
49
+ axiosResponse.data.error
50
+ );
51
+ case 429:
52
+ return new TropipayJSException(
53
+ `${errorMessage} Too many request or rate limited`,
54
+ axiosResponse.status,
55
+ axiosResponse.data.error
56
+ );
57
+ default:
58
+ return new TropipayJSException(
59
+ errorMessage,
60
+ axiosResponse.status,
61
+ axiosResponse.data.error
62
+ );
63
+ }
64
+ } else if (error.request) {
65
+ // Axios request was made but no response received (e.g., network error)
66
+ return new TropipayJSException(
67
+ "Request failed: No response received",
68
+ 500,
69
+ null
70
+ );
71
+ } else {
72
+ // Something else went wrong
73
+ return new TropipayJSException("An error occurred", 500, null);
74
+ }
75
+ } else {
76
+ return new TropipayJSException("An Unknown error occurred", 500, null);
77
+ }
78
+ }
79
+
80
+ export class TropipayJSException extends Error {
81
+ code: number; // Status code
82
+ error: unknown;
83
+ message: string;
84
+ constructor(message: string, code: number, data: unknown) {
85
+ super(message);
86
+ // Set the prototype explicitly.
87
+ Object.setPrototypeOf(this, TropipayJSException.prototype);
88
+ this.code = code;
89
+ this.error = data;
90
+ this.message = message;
91
+ }
92
+ }