cmi-node 1.0.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.
Files changed (197) hide show
  1. package/LICENSE +21 -0
  2. package/dist/constants/confirmationModes.cjs +19 -0
  3. package/dist/constants/confirmationModes.d.ts +5 -0
  4. package/dist/constants/confirmationModes.d.ts.map +1 -0
  5. package/dist/constants/confirmationModes.js.map +1 -0
  6. package/dist/constants/confirmationModes.mjs +15 -0
  7. package/dist/constants/currencies.cjs +73 -0
  8. package/dist/constants/currencies.d.ts +219 -0
  9. package/dist/constants/currencies.d.ts.map +1 -0
  10. package/dist/constants/currencies.js.map +1 -0
  11. package/dist/constants/currencies.mjs +66 -0
  12. package/dist/constants/fields.cjs +54 -0
  13. package/dist/constants/fields.d.ts +9 -0
  14. package/dist/constants/fields.d.ts.map +1 -0
  15. package/dist/constants/fields.js.map +1 -0
  16. package/dist/constants/fields.mjs +48 -0
  17. package/dist/constants/index.cjs +7 -0
  18. package/dist/constants/index.d.ts +7 -0
  19. package/dist/constants/index.d.ts.map +1 -0
  20. package/dist/constants/index.js.map +1 -0
  21. package/dist/constants/index.mjs +7 -0
  22. package/dist/constants/languages.cjs +56 -0
  23. package/dist/constants/languages.d.ts +5 -0
  24. package/dist/constants/languages.d.ts.map +1 -0
  25. package/dist/constants/languages.js.map +1 -0
  26. package/dist/constants/languages.mjs +52 -0
  27. package/dist/constants/storeTypes.cjs +26 -0
  28. package/dist/constants/storeTypes.d.ts +5 -0
  29. package/dist/constants/storeTypes.d.ts.map +1 -0
  30. package/dist/constants/storeTypes.js.map +1 -0
  31. package/dist/constants/storeTypes.mjs +22 -0
  32. package/dist/constants/tranTypes.cjs +22 -0
  33. package/dist/constants/tranTypes.d.ts +5 -0
  34. package/dist/constants/tranTypes.d.ts.map +1 -0
  35. package/dist/constants/tranTypes.js.map +1 -0
  36. package/dist/constants/tranTypes.mjs +18 -0
  37. package/dist/core/CMIPaymentGateway.cjs +94 -0
  38. package/dist/core/CMIPaymentGateway.d.ts +29 -0
  39. package/dist/core/CMIPaymentGateway.d.ts.map +1 -0
  40. package/dist/core/CMIPaymentGateway.js.map +1 -0
  41. package/dist/core/CMIPaymentGateway.mjs +92 -0
  42. package/dist/core/CallbackHandler.cjs +92 -0
  43. package/dist/core/CallbackHandler.d.ts +16 -0
  44. package/dist/core/CallbackHandler.d.ts.map +1 -0
  45. package/dist/core/CallbackHandler.js.map +1 -0
  46. package/dist/core/CallbackHandler.mjs +90 -0
  47. package/dist/core/CallbackVerifier.cjs +92 -0
  48. package/dist/core/CallbackVerifier.d.ts +12 -0
  49. package/dist/core/CallbackVerifier.d.ts.map +1 -0
  50. package/dist/core/CallbackVerifier.js.map +1 -0
  51. package/dist/core/CallbackVerifier.mjs +90 -0
  52. package/dist/core/FormGenerator.cjs +44 -0
  53. package/dist/core/FormGenerator.d.ts +7 -0
  54. package/dist/core/FormGenerator.d.ts.map +1 -0
  55. package/dist/core/FormGenerator.js.map +1 -0
  56. package/dist/core/FormGenerator.mjs +42 -0
  57. package/dist/core/PaymentBuilder.cjs +63 -0
  58. package/dist/core/PaymentBuilder.d.ts +17 -0
  59. package/dist/core/PaymentBuilder.d.ts.map +1 -0
  60. package/dist/core/PaymentBuilder.js.map +1 -0
  61. package/dist/core/PaymentBuilder.mjs +61 -0
  62. package/dist/core/index.cjs +12 -0
  63. package/dist/core/index.d.ts +7 -0
  64. package/dist/core/index.d.ts.map +1 -0
  65. package/dist/core/index.js.map +1 -0
  66. package/dist/core/index.mjs +6 -0
  67. package/dist/index.cjs +44 -0
  68. package/dist/index.d.ts +12 -0
  69. package/dist/index.d.ts.map +1 -0
  70. package/dist/index.js.map +1 -0
  71. package/dist/index.mjs +11 -0
  72. package/dist/logger/index.cjs +55 -0
  73. package/dist/logger/index.d.ts +16 -0
  74. package/dist/logger/index.d.ts.map +1 -0
  75. package/dist/logger/index.js.map +1 -0
  76. package/dist/logger/index.mjs +51 -0
  77. package/dist/middleware/express.middleware.cjs +12 -0
  78. package/dist/middleware/express.middleware.d.ts +5 -0
  79. package/dist/middleware/express.middleware.d.ts.map +1 -0
  80. package/dist/middleware/express.middleware.js.map +1 -0
  81. package/dist/middleware/express.middleware.mjs +9 -0
  82. package/dist/middleware/fastify.helper.cjs +25 -0
  83. package/dist/middleware/fastify.helper.d.ts +6 -0
  84. package/dist/middleware/fastify.helper.d.ts.map +1 -0
  85. package/dist/middleware/fastify.helper.js.map +1 -0
  86. package/dist/middleware/fastify.helper.mjs +22 -0
  87. package/dist/middleware/hono.helper.cjs +32 -0
  88. package/dist/middleware/hono.helper.d.ts +6 -0
  89. package/dist/middleware/hono.helper.d.ts.map +1 -0
  90. package/dist/middleware/hono.helper.js.map +1 -0
  91. package/dist/middleware/hono.helper.mjs +29 -0
  92. package/dist/middleware/index.cjs +6 -0
  93. package/dist/middleware/index.d.ts +6 -0
  94. package/dist/middleware/index.d.ts.map +1 -0
  95. package/dist/middleware/index.js.map +1 -0
  96. package/dist/middleware/index.mjs +6 -0
  97. package/dist/middleware/nestjs.helper.cjs +33 -0
  98. package/dist/middleware/nestjs.helper.d.ts +10 -0
  99. package/dist/middleware/nestjs.helper.d.ts.map +1 -0
  100. package/dist/middleware/nestjs.helper.js.map +1 -0
  101. package/dist/middleware/nestjs.helper.mjs +30 -0
  102. package/dist/middleware/nextjs.helper.cjs +44 -0
  103. package/dist/middleware/nextjs.helper.d.ts +4 -0
  104. package/dist/middleware/nextjs.helper.d.ts.map +1 -0
  105. package/dist/middleware/nextjs.helper.js.map +1 -0
  106. package/dist/middleware/nextjs.helper.mjs +42 -0
  107. package/dist/types/callback-handler.types.cjs +2 -0
  108. package/dist/types/callback-handler.types.d.ts +28 -0
  109. package/dist/types/callback-handler.types.d.ts.map +1 -0
  110. package/dist/types/callback-handler.types.js.map +1 -0
  111. package/dist/types/callback-handler.types.mjs +2 -0
  112. package/dist/types/callback.types.cjs +2 -0
  113. package/dist/types/callback.types.d.ts +14 -0
  114. package/dist/types/callback.types.d.ts.map +1 -0
  115. package/dist/types/callback.types.js.map +1 -0
  116. package/dist/types/callback.types.mjs +2 -0
  117. package/dist/types/config.types.cjs +2 -0
  118. package/dist/types/config.types.d.ts +11 -0
  119. package/dist/types/config.types.d.ts.map +1 -0
  120. package/dist/types/config.types.js.map +1 -0
  121. package/dist/types/config.types.mjs +2 -0
  122. package/dist/types/confirmation-mode.types.cjs +2 -0
  123. package/dist/types/confirmation-mode.types.d.ts +2 -0
  124. package/dist/types/confirmation-mode.types.d.ts.map +1 -0
  125. package/dist/types/confirmation-mode.types.js.map +1 -0
  126. package/dist/types/confirmation-mode.types.mjs +2 -0
  127. package/dist/types/gateway.types.cjs +2 -0
  128. package/dist/types/gateway.types.d.ts +16 -0
  129. package/dist/types/gateway.types.d.ts.map +1 -0
  130. package/dist/types/gateway.types.js.map +1 -0
  131. package/dist/types/gateway.types.mjs +2 -0
  132. package/dist/types/index.cjs +6 -0
  133. package/dist/types/index.d.ts +6 -0
  134. package/dist/types/index.d.ts.map +1 -0
  135. package/dist/types/index.js.map +1 -0
  136. package/dist/types/index.mjs +6 -0
  137. package/dist/types/payment.types.cjs +2 -0
  138. package/dist/types/payment.types.d.ts +29 -0
  139. package/dist/types/payment.types.d.ts.map +1 -0
  140. package/dist/types/payment.types.js.map +1 -0
  141. package/dist/types/payment.types.mjs +2 -0
  142. package/dist/utils/crypto/index.cjs +2 -0
  143. package/dist/utils/crypto/index.d.ts +2 -0
  144. package/dist/utils/crypto/index.d.ts.map +1 -0
  145. package/dist/utils/crypto/index.js.map +1 -0
  146. package/dist/utils/crypto/index.mjs +2 -0
  147. package/dist/utils/crypto/timing-safe.util.cjs +23 -0
  148. package/dist/utils/crypto/timing-safe.util.d.ts +3 -0
  149. package/dist/utils/crypto/timing-safe.util.d.ts.map +1 -0
  150. package/dist/utils/crypto/timing-safe.util.js.map +1 -0
  151. package/dist/utils/crypto/timing-safe.util.mjs +20 -0
  152. package/dist/utils/formatter.util.cjs +42 -0
  153. package/dist/utils/formatter.util.d.ts +9 -0
  154. package/dist/utils/formatter.util.d.ts.map +1 -0
  155. package/dist/utils/formatter.util.js.map +1 -0
  156. package/dist/utils/formatter.util.mjs +40 -0
  157. package/dist/utils/generator.util.cjs +14 -0
  158. package/dist/utils/generator.util.d.ts +5 -0
  159. package/dist/utils/generator.util.d.ts.map +1 -0
  160. package/dist/utils/generator.util.js.map +1 -0
  161. package/dist/utils/generator.util.mjs +12 -0
  162. package/dist/utils/hash.util.cjs +42 -0
  163. package/dist/utils/hash.util.d.ts +4 -0
  164. package/dist/utils/hash.util.d.ts.map +1 -0
  165. package/dist/utils/hash.util.js.map +1 -0
  166. package/dist/utils/hash.util.mjs +40 -0
  167. package/dist/utils/index.cjs +6 -0
  168. package/dist/utils/index.d.ts +6 -0
  169. package/dist/utils/index.d.ts.map +1 -0
  170. package/dist/utils/index.js.map +1 -0
  171. package/dist/utils/index.mjs +6 -0
  172. package/dist/utils/sanitization.util.cjs +26 -0
  173. package/dist/utils/sanitization.util.d.ts +6 -0
  174. package/dist/utils/sanitization.util.d.ts.map +1 -0
  175. package/dist/utils/sanitization.util.js.map +1 -0
  176. package/dist/utils/sanitization.util.mjs +24 -0
  177. package/dist/validators/config.validator.cjs +53 -0
  178. package/dist/validators/config.validator.d.ts +8 -0
  179. package/dist/validators/config.validator.d.ts.map +1 -0
  180. package/dist/validators/config.validator.js.map +1 -0
  181. package/dist/validators/config.validator.mjs +51 -0
  182. package/dist/validators/index.cjs +4 -0
  183. package/dist/validators/index.d.ts +4 -0
  184. package/dist/validators/index.d.ts.map +1 -0
  185. package/dist/validators/index.js.map +1 -0
  186. package/dist/validators/index.mjs +4 -0
  187. package/dist/validators/payment.validator.cjs +161 -0
  188. package/dist/validators/payment.validator.d.ts +7 -0
  189. package/dist/validators/payment.validator.d.ts.map +1 -0
  190. package/dist/validators/payment.validator.js.map +1 -0
  191. package/dist/validators/payment.validator.mjs +159 -0
  192. package/dist/validators/validator.cjs +50 -0
  193. package/dist/validators/validator.d.ts +10 -0
  194. package/dist/validators/validator.d.ts.map +1 -0
  195. package/dist/validators/validator.js.map +1 -0
  196. package/dist/validators/validator.mjs +48 -0
  197. package/package.json +88 -0
@@ -0,0 +1,53 @@
1
+ const { isSupportedStoreType, SUPPORTED_STORE_TYPES, isSupportedTranType, SUPPORTED_TRAN_TYPES, isSupportedConfirmationMode, SUPPORTED_CONFIRMATION_MODES } = require("../constants/index.cjs");
2
+ const { Validator } = require("./validator.cjs");
3
+ class ConfigValidator extends Validator {
4
+ static validate(config) {
5
+ const required = [
6
+ 'storeKey', 'clientId', 'gatewayUrl', 'storetype',
7
+ 'trantype', 'shopUrl'
8
+ ];
9
+ for (const field of required) {
10
+ if (!config[field]) {
11
+ throw new Error(`Missing required config field: ${field}`);
12
+ }
13
+ }
14
+ if (!this.isNumeric(config.clientId.toString())) {
15
+ throw new Error(`clientId must be numeric: ${config.clientId}`);
16
+ }
17
+ if (!this.isValidUrl(config.gatewayUrl) || !this.hasHttpProtocol(config.gatewayUrl)) {
18
+ throw new Error(`Invalid gatewayUrl: ${config.gatewayUrl} or missing http/https protocol`);
19
+ }
20
+ if (!this.isValidUrl(config.shopUrl) || !this.hasHttpProtocol(config.shopUrl)) {
21
+ throw new Error(`Invalid shopUrl: ${config.shopUrl} or missing http/https protocol`);
22
+ }
23
+ if (config.callbackUrl) {
24
+ if (!this.isValidUrl(config.callbackUrl) || !this.hasHttpProtocol(config.callbackUrl)) {
25
+ throw new Error(`Invalid callbackUrl: ${config.callbackUrl} or missing http/https protocol`);
26
+ }
27
+ }
28
+ const normalizedStoreType = config.storetype.toLowerCase();
29
+ if (!isSupportedStoreType(normalizedStoreType)) {
30
+ throw new Error(`Unsupported store type: "${config.storetype}". ` +
31
+ `Supported types (case-insensitive): ${SUPPORTED_STORE_TYPES.join(', ')}`);
32
+ }
33
+ const normalizedTranType = config.trantype.toLowerCase();
34
+ if (!isSupportedTranType(normalizedTranType)) {
35
+ throw new Error(`Unsupported transaction type: "${config.trantype}". ` +
36
+ `Supported types (case-insensitive): ${SUPPORTED_TRAN_TYPES.join(', ')}`);
37
+ }
38
+ }
39
+ static validateConfirmationMode(mode) {
40
+ if (mode === undefined || mode === null || mode === '') {
41
+ return 'auto';
42
+ }
43
+ const normalizedMode = mode.toLowerCase();
44
+ if (!isSupportedConfirmationMode(normalizedMode)) {
45
+ throw new Error(`Unsupported confirmation mode: "${mode}". ` +
46
+ `Supported modes (case-insensitive): ${SUPPORTED_CONFIRMATION_MODES.join(', ')}`);
47
+ }
48
+ return normalizedMode;
49
+ }
50
+ }
51
+ //# sourceMappingURL=config.validator.js.map
52
+
53
+ module.exports.ConfigValidator = ConfigValidator;
@@ -0,0 +1,8 @@
1
+ import { PaymentConfig } from '../types/index.js';
2
+ import { ConfirmationMode } from '../types/index.js';
3
+ import { Validator } from './validator.js';
4
+ export declare class ConfigValidator extends Validator {
5
+ static validate(config: PaymentConfig): void;
6
+ static validateConfirmationMode(mode: string | undefined): ConfirmationMode;
7
+ }
8
+ //# sourceMappingURL=config.validator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.validator.d.ts","sourceRoot":"","sources":["../../src/validators/config.validator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,EAAE,gBAAgB,EAAE,MAAM,QAAQ,CAAC;AAS1C,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,qBAAa,eAAgB,SAAQ,SAAS;IAI5C,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI;IAuD5C,MAAM,CAAC,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,gBAAgB;CAgB5E"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.validator.js","sourceRoot":"","sources":["../../src/validators/config.validator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ import { isSupportedStoreType, SUPPORTED_STORE_TYPES, isSupportedTranType, SUPPORTED_TRAN_TYPES, isSupportedConfirmationMode, SUPPORTED_CONFIRMATION_MODES } from '../constants/index.mjs';
2
+ import { Validator } from './validator.mjs';
3
+ export class ConfigValidator extends Validator {
4
+ static validate(config) {
5
+ const required = [
6
+ 'storeKey', 'clientId', 'gatewayUrl', 'storetype',
7
+ 'trantype', 'shopUrl'
8
+ ];
9
+ for (const field of required) {
10
+ if (!config[field]) {
11
+ throw new Error(`Missing required config field: ${field}`);
12
+ }
13
+ }
14
+ if (!this.isNumeric(config.clientId.toString())) {
15
+ throw new Error(`clientId must be numeric: ${config.clientId}`);
16
+ }
17
+ if (!this.isValidUrl(config.gatewayUrl) || !this.hasHttpProtocol(config.gatewayUrl)) {
18
+ throw new Error(`Invalid gatewayUrl: ${config.gatewayUrl} or missing http/https protocol`);
19
+ }
20
+ if (!this.isValidUrl(config.shopUrl) || !this.hasHttpProtocol(config.shopUrl)) {
21
+ throw new Error(`Invalid shopUrl: ${config.shopUrl} or missing http/https protocol`);
22
+ }
23
+ if (config.callbackUrl) {
24
+ if (!this.isValidUrl(config.callbackUrl) || !this.hasHttpProtocol(config.callbackUrl)) {
25
+ throw new Error(`Invalid callbackUrl: ${config.callbackUrl} or missing http/https protocol`);
26
+ }
27
+ }
28
+ const normalizedStoreType = config.storetype.toLowerCase();
29
+ if (!isSupportedStoreType(normalizedStoreType)) {
30
+ throw new Error(`Unsupported store type: "${config.storetype}". ` +
31
+ `Supported types (case-insensitive): ${SUPPORTED_STORE_TYPES.join(', ')}`);
32
+ }
33
+ const normalizedTranType = config.trantype.toLowerCase();
34
+ if (!isSupportedTranType(normalizedTranType)) {
35
+ throw new Error(`Unsupported transaction type: "${config.trantype}". ` +
36
+ `Supported types (case-insensitive): ${SUPPORTED_TRAN_TYPES.join(', ')}`);
37
+ }
38
+ }
39
+ static validateConfirmationMode(mode) {
40
+ if (mode === undefined || mode === null || mode === '') {
41
+ return 'auto';
42
+ }
43
+ const normalizedMode = mode.toLowerCase();
44
+ if (!isSupportedConfirmationMode(normalizedMode)) {
45
+ throw new Error(`Unsupported confirmation mode: "${mode}". ` +
46
+ `Supported modes (case-insensitive): ${SUPPORTED_CONFIRMATION_MODES.join(', ')}`);
47
+ }
48
+ return normalizedMode;
49
+ }
50
+ }
51
+ //# sourceMappingURL=config.validator.js.map
@@ -0,0 +1,4 @@
1
+ Object.assign(module.exports, require("./config.validator.cjs"));;
2
+ Object.assign(module.exports, require("./payment.validator.cjs"));;
3
+ Object.assign(module.exports, require("./validator.cjs"));;
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,4 @@
1
+ export * from './config.validator.js';
2
+ export * from './payment.validator.js';
3
+ export * from './validator.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/validators/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,aAAa,CAAC"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/validators/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,aAAa,CAAC"}
@@ -0,0 +1,4 @@
1
+ export * from './config.validator.mjs';
2
+ export * from './payment.validator.mjs';
3
+ export * from './validator.mjs';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,161 @@
1
+ const { isSupportedLanguage } = require("../constants/index.cjs");
2
+ const { isSupportedCurrency, isMoroccanDirham } = require("../constants/currencies.cjs");
3
+ const { Validator } = require("./index.cjs");
4
+ class PaymentValidator extends Validator {
5
+ static validate(request) {
6
+ this.checkDuplicateFields(request);
7
+ if (request.amount === undefined || request.amount === null) {
8
+ throw new Error("Amount is required");
9
+ }
10
+ const numericAmount = typeof request.amount === 'string'
11
+ ? parseFloat(request.amount)
12
+ : request.amount;
13
+ if (typeof request.amount === 'string' && !/^-?\d*\.?\d+$/.test(request.amount.trim())) {
14
+ throw new Error(`Invalid amount format: "${request.amount}". Amount must contain only numeric characters.`);
15
+ }
16
+ if (isNaN(numericAmount) || !isFinite(numericAmount)) {
17
+ throw new Error(`Invalid amount: "${request.amount}". Must be a valid number.`);
18
+ }
19
+ if (numericAmount < 1) {
20
+ throw new Error("Amount must be greater than or equal to 1");
21
+ }
22
+ if (!request.okUrl || !this.isValidUrl(request.okUrl)) {
23
+ throw new Error("Valid okUrl is required");
24
+ }
25
+ if (!request.failUrl || !this.isValidUrl(request.failUrl)) {
26
+ throw new Error("Valid failUrl is required");
27
+ }
28
+ if (!this.hasHttpProtocol(request.okUrl)) {
29
+ throw new Error("http/https protocol is required for okUrl");
30
+ }
31
+ if (!this.hasHttpProtocol(request.failUrl)) {
32
+ throw new Error("http/https protocol is required for failUrl");
33
+ }
34
+ if (!request.email || !this.isValidEmail(request.email)) {
35
+ throw new Error("Valid email is required");
36
+ }
37
+ if (!request.BillToName || request.BillToName.trim().length === 0) {
38
+ throw new Error("BillToName is required");
39
+ }
40
+ if (this.hasSpecialCharacters(request.BillToName)) {
41
+ throw new Error("BillToName contains special characters or consecutive spaces which are not allowed");
42
+ }
43
+ if (!request.currency || !isSupportedCurrency(request.currency)) {
44
+ throw new Error(`Unsupported currency: ${request.currency}. Must be a valid currency code (e.g., "MAD") or numeric code (e.g., "504"). Check the supported currencies list.`);
45
+ }
46
+ const isMAD = isMoroccanDirham(request.currency);
47
+ if (!isMAD) {
48
+ throw new Error(`CMI gateway only accepts MAD as the processing currency.\n` +
49
+ `Use currency: "504" or "MAD".\n` +
50
+ `For multi-currency display, use amountCur and symbolCur fields.\n` +
51
+ `Example:\n` +
52
+ ` amount: 100 (in MAD)\n` +
53
+ ` currency: "504"\n` +
54
+ ` amountCur: 10 (customer sees this)\n` +
55
+ ` symbolCur: "840" (USD)`);
56
+ }
57
+ const hasAmountCur = request.amountCur !== undefined && request.amountCur > 0;
58
+ const hasSymbolCur = request.symbolCur !== undefined && request.symbolCur.trim().length > 0;
59
+ if (hasAmountCur !== hasSymbolCur) {
60
+ throw new Error("amountCur and symbolCur must be provided together.\n" +
61
+ "Either provide both (for foreign currency display) or neither (MAD only).");
62
+ }
63
+ if (hasSymbolCur && request.symbolCur) {
64
+ if (!isSupportedCurrency(request.symbolCur)) {
65
+ throw new Error(`Invalid symbolCur: ${request.symbolCur}. Must be a valid currency code.`);
66
+ }
67
+ const displayCurrencyIsMAD = isMoroccanDirham(request.symbolCur);
68
+ if (displayCurrencyIsMAD) {
69
+ throw new Error("symbolCur should not be MAD since the main currency is already MAD.\n" +
70
+ "For MAD-only payments, omit amountCur and symbolCur fields.");
71
+ }
72
+ }
73
+ if (request.lang)
74
+ if (!isSupportedLanguage(request.lang)) {
75
+ throw new Error(`Unsupported language: ${request.lang}. Check the supported languages list.`);
76
+ }
77
+ if (request.phone) {
78
+ throw new Error("The 'phone' field is not supported by the CMI package. Use 'tel' instead.");
79
+ }
80
+ if (request.tel) {
81
+ if (!this.isPhoneNumber(request.tel) ||
82
+ request.tel.trim().length === 0) {
83
+ throw new Error("Invalid phone number format");
84
+ }
85
+ }
86
+ if (request.oid !== undefined) {
87
+ if (typeof request.oid !== 'string' || request.oid.trim().length === 0) {
88
+ throw new Error("oid must be a non-empty string when provided");
89
+ }
90
+ }
91
+ if (request.rnd !== undefined) {
92
+ if (typeof request.rnd !== 'string' || request.rnd.trim().length === 0) {
93
+ throw new Error("rnd must be a non-empty string when provided");
94
+ }
95
+ }
96
+ if (request.hashAlgorithm !== undefined) {
97
+ if (typeof request.hashAlgorithm !== 'string' || request.hashAlgorithm.trim().length === 0) {
98
+ throw new Error("hashAlgorithm cannot be empty when provided. Use 'ver3' or omit the field for default.");
99
+ }
100
+ if (request.hashAlgorithm !== "ver3") {
101
+ throw new Error("hashAlgorithm must be 'ver3'");
102
+ }
103
+ }
104
+ if (request.encoding !== undefined) {
105
+ if (typeof request.encoding !== 'string' || request.encoding.trim().length === 0) {
106
+ throw new Error("encoding cannot be empty when provided. Use 'UTF-8' or omit the field for default.");
107
+ }
108
+ if (request.encoding !== "UTF-8") {
109
+ throw new Error("encoding must be 'UTF-8'");
110
+ }
111
+ }
112
+ if (request.AutoRedirect !== undefined) {
113
+ if (typeof request.AutoRedirect !== "boolean") {
114
+ throw new Error("AutoRedirect must be a boolean (true or false)");
115
+ }
116
+ }
117
+ const billingFields = [
118
+ { key: "BillToCompany", label: "BillToCompany" },
119
+ { key: "BillToStreet1", label: "BillToStreet1" },
120
+ { key: "BillToStreet2", label: "BillToStreet2" },
121
+ { key: "BillToStreet3", label: "BillToStreet3" },
122
+ { key: "BillToCity", label: "BillToCity" },
123
+ { key: "BillToStateProv", label: "BillToStateProv" },
124
+ { key: "BillToPostalCode", label: "BillToPostalCode" },
125
+ { key: "BillToCountry", label: "BillToCountry" },
126
+ ];
127
+ for (const field of billingFields) {
128
+ const value = request[field.key];
129
+ if (value !== undefined && value !== null) {
130
+ if (typeof value !== "string" || value.trim().length === 0) {
131
+ throw new Error(`${field.label} must be a non-empty string`);
132
+ }
133
+ if (this.hasSpecialCharacters(value)) {
134
+ throw new Error(`${field.label} contains special characters or consecutive spaces which are not allowed`);
135
+ }
136
+ }
137
+ }
138
+ }
139
+ static checkDuplicateFields(request) {
140
+ console.log("Checking for duplicate fields in request:", request);
141
+ const keys = Object.keys(request);
142
+ const lowerCaseKeys = new Set();
143
+ const duplicates = [];
144
+ for (const key of keys) {
145
+ const lowerKey = key.toLowerCase();
146
+ if (lowerCaseKeys.has(lowerKey)) {
147
+ duplicates.push(key);
148
+ }
149
+ else {
150
+ lowerCaseKeys.add(lowerKey);
151
+ }
152
+ }
153
+ if (duplicates.length > 0) {
154
+ throw new Error(`Duplicate fields detected (case-insensitive): ${duplicates.join(', ')}. ` +
155
+ `Ensure each field is provided only once.`);
156
+ }
157
+ }
158
+ }
159
+ //# sourceMappingURL=payment.validator.js.map
160
+
161
+ module.exports.PaymentValidator = PaymentValidator;
@@ -0,0 +1,7 @@
1
+ import { PaymentRequest } from "../types/index.js";
2
+ import { Validator } from "./index.js";
3
+ export declare class PaymentValidator extends Validator {
4
+ static validate(request: PaymentRequest): void;
5
+ private static checkDuplicateFields;
6
+ }
7
+ //# sourceMappingURL=payment.validator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"payment.validator.d.ts","sourceRoot":"","sources":["../../src/validators/payment.validator.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,qBAAa,gBAAiB,SAAQ,SAAS;IAC7C,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IA+M9C,OAAO,CAAC,MAAM,CAAC,oBAAoB;CAsBpC"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"payment.validator.js","sourceRoot":"","sources":["../../src/validators/payment.validator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,159 @@
1
+ import { isSupportedLanguage } from '../constants/index.mjs';
2
+ import { isSupportedCurrency, isMoroccanDirham } from '../constants/currencies.mjs';
3
+ import { Validator } from './index.mjs';
4
+ export class PaymentValidator extends Validator {
5
+ static validate(request) {
6
+ this.checkDuplicateFields(request);
7
+ if (request.amount === undefined || request.amount === null) {
8
+ throw new Error("Amount is required");
9
+ }
10
+ const numericAmount = typeof request.amount === 'string'
11
+ ? parseFloat(request.amount)
12
+ : request.amount;
13
+ if (typeof request.amount === 'string' && !/^-?\d*\.?\d+$/.test(request.amount.trim())) {
14
+ throw new Error(`Invalid amount format: "${request.amount}". Amount must contain only numeric characters.`);
15
+ }
16
+ if (isNaN(numericAmount) || !isFinite(numericAmount)) {
17
+ throw new Error(`Invalid amount: "${request.amount}". Must be a valid number.`);
18
+ }
19
+ if (numericAmount < 1) {
20
+ throw new Error("Amount must be greater than or equal to 1");
21
+ }
22
+ if (!request.okUrl || !this.isValidUrl(request.okUrl)) {
23
+ throw new Error("Valid okUrl is required");
24
+ }
25
+ if (!request.failUrl || !this.isValidUrl(request.failUrl)) {
26
+ throw new Error("Valid failUrl is required");
27
+ }
28
+ if (!this.hasHttpProtocol(request.okUrl)) {
29
+ throw new Error("http/https protocol is required for okUrl");
30
+ }
31
+ if (!this.hasHttpProtocol(request.failUrl)) {
32
+ throw new Error("http/https protocol is required for failUrl");
33
+ }
34
+ if (!request.email || !this.isValidEmail(request.email)) {
35
+ throw new Error("Valid email is required");
36
+ }
37
+ if (!request.BillToName || request.BillToName.trim().length === 0) {
38
+ throw new Error("BillToName is required");
39
+ }
40
+ if (this.hasSpecialCharacters(request.BillToName)) {
41
+ throw new Error("BillToName contains special characters or consecutive spaces which are not allowed");
42
+ }
43
+ if (!request.currency || !isSupportedCurrency(request.currency)) {
44
+ throw new Error(`Unsupported currency: ${request.currency}. Must be a valid currency code (e.g., "MAD") or numeric code (e.g., "504"). Check the supported currencies list.`);
45
+ }
46
+ const isMAD = isMoroccanDirham(request.currency);
47
+ if (!isMAD) {
48
+ throw new Error(`CMI gateway only accepts MAD as the processing currency.\n` +
49
+ `Use currency: "504" or "MAD".\n` +
50
+ `For multi-currency display, use amountCur and symbolCur fields.\n` +
51
+ `Example:\n` +
52
+ ` amount: 100 (in MAD)\n` +
53
+ ` currency: "504"\n` +
54
+ ` amountCur: 10 (customer sees this)\n` +
55
+ ` symbolCur: "840" (USD)`);
56
+ }
57
+ const hasAmountCur = request.amountCur !== undefined && request.amountCur > 0;
58
+ const hasSymbolCur = request.symbolCur !== undefined && request.symbolCur.trim().length > 0;
59
+ if (hasAmountCur !== hasSymbolCur) {
60
+ throw new Error("amountCur and symbolCur must be provided together.\n" +
61
+ "Either provide both (for foreign currency display) or neither (MAD only).");
62
+ }
63
+ if (hasSymbolCur && request.symbolCur) {
64
+ if (!isSupportedCurrency(request.symbolCur)) {
65
+ throw new Error(`Invalid symbolCur: ${request.symbolCur}. Must be a valid currency code.`);
66
+ }
67
+ const displayCurrencyIsMAD = isMoroccanDirham(request.symbolCur);
68
+ if (displayCurrencyIsMAD) {
69
+ throw new Error("symbolCur should not be MAD since the main currency is already MAD.\n" +
70
+ "For MAD-only payments, omit amountCur and symbolCur fields.");
71
+ }
72
+ }
73
+ if (request.lang)
74
+ if (!isSupportedLanguage(request.lang)) {
75
+ throw new Error(`Unsupported language: ${request.lang}. Check the supported languages list.`);
76
+ }
77
+ if (request.phone) {
78
+ throw new Error("The 'phone' field is not supported by the CMI package. Use 'tel' instead.");
79
+ }
80
+ if (request.tel) {
81
+ if (!this.isPhoneNumber(request.tel) ||
82
+ request.tel.trim().length === 0) {
83
+ throw new Error("Invalid phone number format");
84
+ }
85
+ }
86
+ if (request.oid !== undefined) {
87
+ if (typeof request.oid !== 'string' || request.oid.trim().length === 0) {
88
+ throw new Error("oid must be a non-empty string when provided");
89
+ }
90
+ }
91
+ if (request.rnd !== undefined) {
92
+ if (typeof request.rnd !== 'string' || request.rnd.trim().length === 0) {
93
+ throw new Error("rnd must be a non-empty string when provided");
94
+ }
95
+ }
96
+ if (request.hashAlgorithm !== undefined) {
97
+ if (typeof request.hashAlgorithm !== 'string' || request.hashAlgorithm.trim().length === 0) {
98
+ throw new Error("hashAlgorithm cannot be empty when provided. Use 'ver3' or omit the field for default.");
99
+ }
100
+ if (request.hashAlgorithm !== "ver3") {
101
+ throw new Error("hashAlgorithm must be 'ver3'");
102
+ }
103
+ }
104
+ if (request.encoding !== undefined) {
105
+ if (typeof request.encoding !== 'string' || request.encoding.trim().length === 0) {
106
+ throw new Error("encoding cannot be empty when provided. Use 'UTF-8' or omit the field for default.");
107
+ }
108
+ if (request.encoding !== "UTF-8") {
109
+ throw new Error("encoding must be 'UTF-8'");
110
+ }
111
+ }
112
+ if (request.AutoRedirect !== undefined) {
113
+ if (typeof request.AutoRedirect !== "boolean") {
114
+ throw new Error("AutoRedirect must be a boolean (true or false)");
115
+ }
116
+ }
117
+ const billingFields = [
118
+ { key: "BillToCompany", label: "BillToCompany" },
119
+ { key: "BillToStreet1", label: "BillToStreet1" },
120
+ { key: "BillToStreet2", label: "BillToStreet2" },
121
+ { key: "BillToStreet3", label: "BillToStreet3" },
122
+ { key: "BillToCity", label: "BillToCity" },
123
+ { key: "BillToStateProv", label: "BillToStateProv" },
124
+ { key: "BillToPostalCode", label: "BillToPostalCode" },
125
+ { key: "BillToCountry", label: "BillToCountry" },
126
+ ];
127
+ for (const field of billingFields) {
128
+ const value = request[field.key];
129
+ if (value !== undefined && value !== null) {
130
+ if (typeof value !== "string" || value.trim().length === 0) {
131
+ throw new Error(`${field.label} must be a non-empty string`);
132
+ }
133
+ if (this.hasSpecialCharacters(value)) {
134
+ throw new Error(`${field.label} contains special characters or consecutive spaces which are not allowed`);
135
+ }
136
+ }
137
+ }
138
+ }
139
+ static checkDuplicateFields(request) {
140
+ console.log("Checking for duplicate fields in request:", request);
141
+ const keys = Object.keys(request);
142
+ const lowerCaseKeys = new Set();
143
+ const duplicates = [];
144
+ for (const key of keys) {
145
+ const lowerKey = key.toLowerCase();
146
+ if (lowerCaseKeys.has(lowerKey)) {
147
+ duplicates.push(key);
148
+ }
149
+ else {
150
+ lowerCaseKeys.add(lowerKey);
151
+ }
152
+ }
153
+ if (duplicates.length > 0) {
154
+ throw new Error(`Duplicate fields detected (case-insensitive): ${duplicates.join(', ')}. ` +
155
+ `Ensure each field is provided only once.`);
156
+ }
157
+ }
158
+ }
159
+ //# sourceMappingURL=payment.validator.js.map
@@ -0,0 +1,50 @@
1
+ class Validator {
2
+ static isValidUrl(url) {
3
+ try {
4
+ new URL(url);
5
+ return true;
6
+ }
7
+ catch {
8
+ return false;
9
+ }
10
+ }
11
+ static hasHttpProtocol(url) {
12
+ try {
13
+ const urlObj = new URL(url);
14
+ return urlObj.protocol === "http:" || urlObj.protocol === "https:";
15
+ }
16
+ catch {
17
+ return false;
18
+ }
19
+ }
20
+ static isValidEmail(email) {
21
+ const emailRegex = /^[a-zA-Z0-9]+([._+-][a-zA-Z0-9]+)*@[a-zA-Z0-9]+([.-][a-zA-Z0-9]+)*\.[a-zA-Z]{2,}$/;
22
+ return emailRegex.test(email);
23
+ }
24
+ static hasSpecialCharacters(str) {
25
+ const regex = /^[a-zA-Z0-9]+(\s+[a-zA-Z0-9]+)*$/;
26
+ if (/\s{2,}/.test(str)) {
27
+ return true;
28
+ }
29
+ return !regex.test(str);
30
+ }
31
+ static isPhoneNumber(phone) {
32
+ const trimmed = phone.trim();
33
+ const formatRegex = /^[\+\d][\d\s\-()]*$/;
34
+ if (!formatRegex.test(trimmed)) {
35
+ return false;
36
+ }
37
+ const cleaned = trimmed.replace(/[\s\-()]/g, "");
38
+ const phoneRegex = /^\+?[1-9]\d{9,14}$/;
39
+ return phoneRegex.test(cleaned);
40
+ }
41
+ static isNumeric(value) {
42
+ return /^-?\d*\.?\d+$/.test(value.trim());
43
+ }
44
+ static isEmpty(value) {
45
+ return value.trim().length === 0;
46
+ }
47
+ }
48
+ //# sourceMappingURL=validator.js.map
49
+
50
+ module.exports.Validator = Validator;
@@ -0,0 +1,10 @@
1
+ export declare class Validator {
2
+ protected static isValidUrl(url: string): boolean;
3
+ protected static hasHttpProtocol(url: string): boolean;
4
+ protected static isValidEmail(email: string): boolean;
5
+ protected static hasSpecialCharacters(str: string): boolean;
6
+ protected static isPhoneNumber(phone: string): boolean;
7
+ protected static isNumeric(value: string): boolean;
8
+ protected static isEmpty(value: string): boolean;
9
+ }
10
+ //# sourceMappingURL=validator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../src/validators/validator.ts"],"names":[],"mappings":"AAAA,qBAAa,SAAS;IACpB,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAUjD,SAAS,CAAC,MAAM,CAAC,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAStD,SAAS,CAAC,MAAM,CAAC,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAOrD,SAAS,CAAC,MAAM,CAAC,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAa3D,SAAS,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAqBtD,SAAS,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAIlD,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;CAGjD"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validator.js","sourceRoot":"","sources":["../../src/validators/validator.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,SAAS;IACV,MAAM,CAAC,UAAU,CAAC,GAAW;QACrC,IAAI,CAAC;YACH,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;YACb,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAGS,MAAM,CAAC,eAAe,CAAC,GAAW;QAC1C,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;YAC5B,OAAO,MAAM,CAAC,QAAQ,KAAK,OAAO,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,CAAC;QACrE,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAES,MAAM,CAAC,YAAY,CAAC,KAAa;QAEzC,MAAM,UAAU,GACd,mFAAmF,CAAC;QACtF,OAAO,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAChC,CAAC;IAES,MAAM,CAAC,oBAAoB,CAAC,GAAW;QAG/C,MAAM,KAAK,GAAG,kCAAkC,CAAC;QAGjD,IAAI,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YACvB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC1B,CAAC;IAES,MAAM,CAAC,aAAa,CAAC,KAAa;QAC1C,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;QAK7B,MAAM,WAAW,GAAG,qBAAqB,CAAC;QAC1C,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YAC/B,OAAO,KAAK,CAAC;QACf,CAAC;QAGD,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QAGjD,MAAM,UAAU,GAAG,oBAAoB,CAAC;QAExC,OAAO,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAClC,CAAC;IAGS,MAAM,CAAC,SAAS,CAAC,KAAa;QACtC,OAAO,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IAC5C,CAAC;IAES,MAAM,CAAC,OAAO,CAAC,KAAa;QACpC,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,CAAC;IACnC,CAAC;CACF"}
@@ -0,0 +1,48 @@
1
+ export class Validator {
2
+ static isValidUrl(url) {
3
+ try {
4
+ new URL(url);
5
+ return true;
6
+ }
7
+ catch {
8
+ return false;
9
+ }
10
+ }
11
+ static hasHttpProtocol(url) {
12
+ try {
13
+ const urlObj = new URL(url);
14
+ return urlObj.protocol === "http:" || urlObj.protocol === "https:";
15
+ }
16
+ catch {
17
+ return false;
18
+ }
19
+ }
20
+ static isValidEmail(email) {
21
+ const emailRegex = /^[a-zA-Z0-9]+([._+-][a-zA-Z0-9]+)*@[a-zA-Z0-9]+([.-][a-zA-Z0-9]+)*\.[a-zA-Z]{2,}$/;
22
+ return emailRegex.test(email);
23
+ }
24
+ static hasSpecialCharacters(str) {
25
+ const regex = /^[a-zA-Z0-9]+(\s+[a-zA-Z0-9]+)*$/;
26
+ if (/\s{2,}/.test(str)) {
27
+ return true;
28
+ }
29
+ return !regex.test(str);
30
+ }
31
+ static isPhoneNumber(phone) {
32
+ const trimmed = phone.trim();
33
+ const formatRegex = /^[\+\d][\d\s\-()]*$/;
34
+ if (!formatRegex.test(trimmed)) {
35
+ return false;
36
+ }
37
+ const cleaned = trimmed.replace(/[\s\-()]/g, "");
38
+ const phoneRegex = /^\+?[1-9]\d{9,14}$/;
39
+ return phoneRegex.test(cleaned);
40
+ }
41
+ static isNumeric(value) {
42
+ return /^-?\d*\.?\d+$/.test(value.trim());
43
+ }
44
+ static isEmpty(value) {
45
+ return value.trim().length === 0;
46
+ }
47
+ }
48
+ //# sourceMappingURL=validator.js.map