mvc-common-toolkit 1.43.10 → 1.44.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 (210) hide show
  1. package/dist/src/constants.d.ts +59 -0
  2. package/dist/src/constants.js +69 -0
  3. package/dist/src/constants.js.map +1 -0
  4. package/dist/src/gateways/alibaba-cloud-gateway.d.ts +30 -0
  5. package/dist/src/gateways/alibaba-cloud-gateway.js +120 -0
  6. package/dist/src/gateways/alibaba-cloud-gateway.js.map +1 -0
  7. package/dist/src/gateways/http-audit-gateway.d.ts +20 -0
  8. package/dist/src/gateways/http-audit-gateway.js +76 -0
  9. package/dist/src/gateways/http-audit-gateway.js.map +1 -0
  10. package/dist/src/gateways/index.d.ts +5 -0
  11. package/dist/src/gateways/index.js +22 -0
  12. package/dist/src/gateways/index.js.map +1 -0
  13. package/dist/src/gateways/internal-auth-gateway.d.ts +8 -0
  14. package/dist/src/gateways/internal-auth-gateway.js +40 -0
  15. package/dist/src/gateways/internal-auth-gateway.js.map +1 -0
  16. package/dist/src/gateways/stdout-audit-gateway.d.ts +7 -0
  17. package/dist/src/gateways/stdout-audit-gateway.js +25 -0
  18. package/dist/src/gateways/stdout-audit-gateway.js.map +1 -0
  19. package/dist/src/gateways/webhook-audit-gateway.d.ts +14 -0
  20. package/dist/src/gateways/webhook-audit-gateway.js +27 -0
  21. package/dist/src/gateways/webhook-audit-gateway.js.map +1 -0
  22. package/dist/src/interfaces.d.ts +218 -0
  23. package/dist/src/interfaces.js +3 -0
  24. package/dist/src/interfaces.js.map +1 -0
  25. package/dist/src/models/audit-log.d.ts +77 -0
  26. package/dist/src/models/audit-log.js +92 -0
  27. package/dist/src/models/audit-log.js.map +1 -0
  28. package/dist/src/models/index.d.ts +1 -0
  29. package/dist/src/models/index.js +18 -0
  30. package/dist/src/models/index.js.map +1 -0
  31. package/dist/src/pkg/array-helper.d.ts +1 -0
  32. package/dist/src/pkg/array-helper.js +12 -0
  33. package/dist/src/pkg/array-helper.js.map +1 -0
  34. package/dist/src/pkg/bcrypt-helper.d.ts +2 -0
  35. package/dist/src/pkg/bcrypt-helper.js +36 -0
  36. package/dist/src/pkg/bcrypt-helper.js.map +1 -0
  37. package/dist/src/pkg/crypto-helper.d.ts +2 -0
  38. package/dist/src/pkg/crypto-helper.js +16 -0
  39. package/dist/src/pkg/crypto-helper.js.map +1 -0
  40. package/dist/src/pkg/encryption-helper.d.ts +18 -0
  41. package/dist/src/pkg/encryption-helper.js +89 -0
  42. package/dist/src/pkg/encryption-helper.js.map +1 -0
  43. package/dist/src/pkg/encryption-helper.spec.d.ts +1 -0
  44. package/dist/src/pkg/encryption-helper.spec.js +238 -0
  45. package/dist/src/pkg/encryption-helper.spec.js.map +1 -0
  46. package/dist/src/pkg/filter-helper.d.ts +2 -0
  47. package/dist/src/pkg/filter-helper.js +102 -0
  48. package/dist/src/pkg/filter-helper.js.map +1 -0
  49. package/dist/src/pkg/filter-helper.spec.d.ts +1 -0
  50. package/dist/src/pkg/filter-helper.spec.js +94 -0
  51. package/dist/src/pkg/filter-helper.spec.js.map +1 -0
  52. package/dist/src/pkg/geoip-helper.d.ts +2 -0
  53. package/dist/src/pkg/geoip-helper.js +32 -0
  54. package/dist/src/pkg/geoip-helper.js.map +1 -0
  55. package/dist/src/pkg/hash-helper.d.ts +1 -0
  56. package/dist/src/pkg/hash-helper.js +37 -0
  57. package/dist/src/pkg/hash-helper.js.map +1 -0
  58. package/dist/src/pkg/http-request-utils.d.ts +4 -0
  59. package/dist/src/pkg/http-request-utils.js +55 -0
  60. package/dist/src/pkg/http-request-utils.js.map +1 -0
  61. package/dist/src/pkg/index.d.ts +19 -0
  62. package/dist/src/pkg/index.js +46 -0
  63. package/dist/src/pkg/index.js.map +1 -0
  64. package/dist/src/pkg/key-helper.d.ts +2 -0
  65. package/dist/src/pkg/key-helper.js +20 -0
  66. package/dist/src/pkg/key-helper.js.map +1 -0
  67. package/dist/src/pkg/logger.d.ts +9 -0
  68. package/dist/src/pkg/logger.js +23 -0
  69. package/dist/src/pkg/logger.js.map +1 -0
  70. package/dist/src/pkg/object-helper.d.ts +2 -0
  71. package/dist/src/pkg/object-helper.js +37 -0
  72. package/dist/src/pkg/object-helper.js.map +1 -0
  73. package/dist/src/pkg/paginated-cache-registry.d.ts +8 -0
  74. package/dist/src/pkg/paginated-cache-registry.js +23 -0
  75. package/dist/src/pkg/paginated-cache-registry.js.map +1 -0
  76. package/dist/src/pkg/query-helper.d.ts +3 -0
  77. package/dist/src/pkg/query-helper.js +60 -0
  78. package/dist/src/pkg/query-helper.js.map +1 -0
  79. package/dist/src/pkg/referral-tree-utils.d.ts +33 -0
  80. package/dist/src/pkg/referral-tree-utils.js +71 -0
  81. package/dist/src/pkg/referral-tree-utils.js.map +1 -0
  82. package/dist/src/pkg/scripts/index.d.ts +1 -0
  83. package/dist/src/pkg/scripts/index.js +28 -0
  84. package/dist/src/pkg/scripts/index.js.map +1 -0
  85. package/dist/src/pkg/scripts/lua.d.ts +10 -0
  86. package/dist/src/pkg/scripts/lua.js +109 -0
  87. package/dist/src/pkg/scripts/lua.js.map +1 -0
  88. package/dist/src/pkg/sort-helper.d.ts +3 -0
  89. package/dist/src/pkg/sort-helper.js +18 -0
  90. package/dist/src/pkg/sort-helper.js.map +1 -0
  91. package/dist/src/pkg/string-utils.d.ts +10 -0
  92. package/dist/src/pkg/string-utils.js +79 -0
  93. package/dist/src/pkg/string-utils.js.map +1 -0
  94. package/dist/src/pkg/task-helper.d.ts +2 -0
  95. package/dist/src/pkg/task-helper.js +30 -0
  96. package/dist/src/pkg/task-helper.js.map +1 -0
  97. package/dist/src/pkg/trading-pair-helper.d.ts +9 -0
  98. package/dist/src/pkg/trading-pair-helper.js +44 -0
  99. package/dist/src/pkg/trading-pair-helper.js.map +1 -0
  100. package/dist/src/pkg/trading-pair-helper.spec.d.ts +1 -0
  101. package/dist/src/pkg/trading-pair-helper.spec.js +132 -0
  102. package/dist/src/pkg/trading-pair-helper.spec.js.map +1 -0
  103. package/dist/src/pkg/workflow/delayed-task-registry.d.ts +10 -0
  104. package/dist/src/pkg/workflow/delayed-task-registry.js +67 -0
  105. package/dist/src/pkg/workflow/delayed-task-registry.js.map +1 -0
  106. package/dist/src/pkg/workflow/delayed-task.d.ts +18 -0
  107. package/dist/src/pkg/workflow/delayed-task.js +95 -0
  108. package/dist/src/pkg/workflow/delayed-task.js.map +1 -0
  109. package/dist/src/pkg/workflow/index.d.ts +5 -0
  110. package/dist/src/pkg/workflow/index.js +22 -0
  111. package/dist/src/pkg/workflow/index.js.map +1 -0
  112. package/dist/src/pkg/workflow/processing-milestone.d.ts +18 -0
  113. package/dist/src/pkg/workflow/processing-milestone.js +39 -0
  114. package/dist/src/pkg/workflow/processing-milestone.js.map +1 -0
  115. package/dist/src/pkg/workflow/retry-task.d.ts +24 -0
  116. package/dist/src/pkg/workflow/retry-task.js +89 -0
  117. package/dist/src/pkg/workflow/retry-task.js.map +1 -0
  118. package/dist/src/pkg/workflow/retry-task.spec.d.ts +1 -0
  119. package/dist/src/pkg/workflow/retry-task.spec.js +145 -0
  120. package/dist/src/pkg/workflow/retry-task.spec.js.map +1 -0
  121. package/dist/src/pkg/workflow/sync-taskqueue.d.ts +32 -0
  122. package/dist/src/pkg/workflow/sync-taskqueue.js +108 -0
  123. package/dist/src/pkg/workflow/sync-taskqueue.js.map +1 -0
  124. package/dist/src/pkg/worksheet.utils.d.ts +27 -0
  125. package/dist/src/pkg/worksheet.utils.js +116 -0
  126. package/dist/src/pkg/worksheet.utils.js.map +1 -0
  127. package/dist/src/services/audit-service.d.ts +7 -0
  128. package/dist/src/services/audit-service.js +32 -0
  129. package/dist/src/services/audit-service.js.map +1 -0
  130. package/dist/src/services/excel.service.d.ts +25 -0
  131. package/dist/src/services/excel.service.js +95 -0
  132. package/dist/src/services/excel.service.js.map +1 -0
  133. package/dist/src/services/http-service.d.ts +7 -0
  134. package/dist/src/services/http-service.js +67 -0
  135. package/dist/src/services/http-service.js.map +1 -0
  136. package/dist/src/services/index.d.ts +8 -0
  137. package/dist/src/services/index.js +25 -0
  138. package/dist/src/services/index.js.map +1 -0
  139. package/dist/src/services/kafka-service.d.ts +15 -0
  140. package/dist/src/services/kafka-service.js +68 -0
  141. package/dist/src/services/kafka-service.js.map +1 -0
  142. package/dist/src/services/mailer-service.d.ts +15 -0
  143. package/dist/src/services/mailer-service.js +44 -0
  144. package/dist/src/services/mailer-service.js.map +1 -0
  145. package/dist/src/services/paginated-cache.d.ts +16 -0
  146. package/dist/src/services/paginated-cache.js +115 -0
  147. package/dist/src/services/paginated-cache.js.map +1 -0
  148. package/dist/src/services/paginated-cache.spec.d.ts +1 -0
  149. package/dist/src/services/paginated-cache.spec.js +284 -0
  150. package/dist/src/services/paginated-cache.spec.js.map +1 -0
  151. package/dist/src/services/redis-service.d.ts +33 -0
  152. package/dist/src/services/redis-service.js +230 -0
  153. package/dist/src/services/redis-service.js.map +1 -0
  154. package/dist/src/services/security-service.d.ts +11 -0
  155. package/dist/src/services/security-service.js +68 -0
  156. package/dist/src/services/security-service.js.map +1 -0
  157. package/dist/tsconfig.tsbuildinfo +1 -1
  158. package/package.json +1 -1
  159. package/src/constants.ts +66 -0
  160. package/src/gateways/alibaba-cloud-gateway.ts +127 -0
  161. package/src/gateways/http-audit-gateway.ts +104 -0
  162. package/src/gateways/index.ts +5 -0
  163. package/src/gateways/internal-auth-gateway.ts +42 -0
  164. package/src/gateways/stdout-audit-gateway.ts +23 -0
  165. package/src/gateways/webhook-audit-gateway.ts +33 -0
  166. package/src/interfaces.ts +304 -0
  167. package/src/models/audit-log.ts +126 -0
  168. package/src/models/index.ts +1 -0
  169. package/src/pkg/array-helper.ts +7 -0
  170. package/src/pkg/bcrypt-helper.ts +9 -0
  171. package/src/pkg/crypto-helper.ts +18 -0
  172. package/src/pkg/encryption-helper.spec.ts +423 -0
  173. package/src/pkg/encryption-helper.ts +155 -0
  174. package/src/pkg/filter-helper.spec.ts +105 -0
  175. package/src/pkg/filter-helper.ts +139 -0
  176. package/src/pkg/geoip-helper.ts +5 -0
  177. package/src/pkg/hash-helper.ts +12 -0
  178. package/src/pkg/http-request-utils.ts +75 -0
  179. package/src/pkg/index.ts +19 -0
  180. package/src/pkg/key-helper.ts +20 -0
  181. package/src/pkg/logger.ts +23 -0
  182. package/src/pkg/object-helper.ts +42 -0
  183. package/src/pkg/paginated-cache-registry.ts +25 -0
  184. package/src/pkg/query-helper.ts +79 -0
  185. package/src/pkg/referral-tree-utils.ts +165 -0
  186. package/src/pkg/scripts/index.ts +1 -0
  187. package/src/pkg/scripts/lua.ts +112 -0
  188. package/src/pkg/sort-helper.ts +19 -0
  189. package/src/pkg/string-utils.ts +104 -0
  190. package/src/pkg/task-helper.ts +25 -0
  191. package/src/pkg/trading-pair-helper.spec.ts +146 -0
  192. package/src/pkg/trading-pair-helper.ts +78 -0
  193. package/src/pkg/workflow/delayed-task-registry.ts +54 -0
  194. package/src/pkg/workflow/delayed-task.ts +106 -0
  195. package/src/pkg/workflow/index.ts +5 -0
  196. package/src/pkg/workflow/processing-milestone.ts +54 -0
  197. package/src/pkg/workflow/retry-task.spec.ts +194 -0
  198. package/src/pkg/workflow/retry-task.ts +119 -0
  199. package/src/pkg/workflow/sync-taskqueue.ts +118 -0
  200. package/src/pkg/worksheet.utils.ts +178 -0
  201. package/src/services/audit-service.ts +22 -0
  202. package/src/services/excel.service.ts +103 -0
  203. package/src/services/http-service.ts +71 -0
  204. package/src/services/index.ts +8 -0
  205. package/src/services/kafka-service.ts +81 -0
  206. package/src/services/mailer-service.ts +43 -0
  207. package/src/services/paginated-cache.spec.ts +519 -0
  208. package/src/services/paginated-cache.ts +122 -0
  209. package/src/services/redis-service.ts +238 -0
  210. package/src/services/security-service.ts +80 -0
@@ -0,0 +1,165 @@
1
+ import { faker } from "@faker-js/faker";
2
+
3
+ import { stringUtils } from ".";
4
+
5
+ interface UserConfig {
6
+ rootRefCode?: string;
7
+ password: string;
8
+ }
9
+
10
+ interface User {
11
+ parentRefCode: string;
12
+ refCode: string;
13
+ password: string;
14
+ email: string;
15
+ children: User[];
16
+ }
17
+
18
+ interface NormalizedUser {
19
+ parentRefCode: string;
20
+ refCode: string;
21
+ password: string;
22
+ email: string;
23
+ }
24
+
25
+ interface ReferralTreeConfig {
26
+ noOfLevels: number;
27
+ minChildPerNode: number;
28
+ maxChildPerNode: number;
29
+ mustHaveChildPerNode: number;
30
+ userConfig: UserConfig;
31
+ passwordHasher?: (password: string) => Promise<string>;
32
+ refCodeGenerator?: () => string;
33
+ addAdditionalData?: () => Promise<Record<string, any>>;
34
+ }
35
+
36
+ const defaultRefcodeGenerator = () =>
37
+ stringUtils.generateRandomId().slice(10).toUpperCase();
38
+
39
+ export const generateReferralTree = async (data: ReferralTreeConfig) => {
40
+ const {
41
+ maxChildPerNode,
42
+ minChildPerNode,
43
+ mustHaveChildPerNode,
44
+ noOfLevels,
45
+ userConfig,
46
+ passwordHasher,
47
+ refCodeGenerator,
48
+ addAdditionalData = () => {},
49
+ } = data;
50
+
51
+ const hashedPassword = await passwordHasher(userConfig.password);
52
+
53
+ const rootUser = await genNewUser(null, {
54
+ hashedPassword,
55
+ additionalDataGenerator: addAdditionalData,
56
+ refCodeGenerator: refCodeGenerator || defaultRefcodeGenerator,
57
+ });
58
+
59
+ const totalUsersToInsert: NormalizedUser[] = [normalizeUser(rootUser)];
60
+
61
+ let currentLayerUsers: User[] = [rootUser];
62
+ let totalUsersCount = currentLayerUsers.length;
63
+
64
+ for (let currentLevel = 0; currentLevel < noOfLevels; currentLevel++) {
65
+ const allChildUserCreated: User[] = [];
66
+
67
+ // Handle the node where the number of children is required
68
+ const nodeSelectedAsRequired = currentLayerUsers[0];
69
+ for (let i = 0; i < mustHaveChildPerNode; i++) {
70
+ const newUser = await genNewUser(nodeSelectedAsRequired.refCode, {
71
+ hashedPassword,
72
+ refCodeGenerator: refCodeGenerator || defaultRefcodeGenerator,
73
+ additionalDataGenerator: addAdditionalData,
74
+ });
75
+
76
+ allChildUserCreated.push(newUser);
77
+ nodeSelectedAsRequired.children.push(newUser);
78
+ }
79
+
80
+ // Handle the nodes where the number of children is within range.
81
+ // Exclude the first user as it's already processed
82
+ await Promise.all(
83
+ currentLayerUsers.slice(1, currentLayerUsers.length).map(async (user) => {
84
+ const noOfChildNodes = faker.helpers.rangeToNumber({
85
+ min: minChildPerNode,
86
+ max: maxChildPerNode,
87
+ });
88
+
89
+ for (let i = 0; i < noOfChildNodes; i++) {
90
+ const newUser = await genNewUser(user.refCode, {
91
+ hashedPassword,
92
+ refCodeGenerator: refCodeGenerator || defaultRefcodeGenerator,
93
+ additionalDataGenerator: addAdditionalData,
94
+ });
95
+
96
+ allChildUserCreated.push(newUser);
97
+ user.children.push(newUser);
98
+ }
99
+ })
100
+ );
101
+
102
+ // Move on to next layer
103
+ const normalizedUsers: Omit<User, "children">[] =
104
+ allChildUserCreated.map(normalizeUser);
105
+
106
+ totalUsersToInsert.push(...normalizedUsers);
107
+ currentLayerUsers = allChildUserCreated;
108
+ totalUsersCount += currentLayerUsers.length;
109
+ }
110
+
111
+ return { rootUser, totalUsersCount, totalUsersToInsert };
112
+ };
113
+
114
+ const normalizeUser = (user: User) => {
115
+ const cloned = JSON.parse(JSON.stringify(user));
116
+ delete cloned.children;
117
+
118
+ return cloned;
119
+ };
120
+
121
+ const genNewUser = async (
122
+ parentRefCode: string,
123
+ { hashedPassword, refCodeGenerator, additionalDataGenerator }
124
+ ): Promise<User> => {
125
+ const additionalData = await additionalDataGenerator();
126
+
127
+ return {
128
+ parentRefCode,
129
+ password: hashedPassword,
130
+ email: faker.internet.email().toLowerCase(),
131
+ children: [],
132
+ refCode: refCodeGenerator(),
133
+ ...additionalData,
134
+ };
135
+ };
136
+
137
+ // generateReferralTree({
138
+ // maxChildPerNode: 2,
139
+ // minChildPerNode: 1,
140
+ // mustHaveChildPerNode: 5,
141
+ // noOfLevels: 5,
142
+ // passwordHasher: async (data) => data,
143
+ // addAdditionalData: async () => {
144
+ // return {
145
+ // fullName: faker.person.fullName(),
146
+ // };
147
+ // },
148
+ // userConfig: {
149
+ // password: "12345",
150
+ // rootRefCode: "ABCD1234",
151
+ // },
152
+ // })
153
+ // .then((data) => {
154
+ // console.log(data.totalUsersCount);
155
+ // fs.writeFileSync(
156
+ // path.resolve(__dirname, "referral_tree.json"),
157
+ // Buffer.from(JSON.stringify(data.rootUser))
158
+ // );
159
+
160
+ // fs.writeFileSync(
161
+ // path.resolve(__dirname, "referral_users.json"),
162
+ // Buffer.from(JSON.stringify(data.totalUsersToInsert))
163
+ // );
164
+ // })
165
+ // .catch((e) => console.error(e));
@@ -0,0 +1 @@
1
+ export * as luaScripts from "./lua";
@@ -0,0 +1,112 @@
1
+ export const IncrByAndSetTTLIfNotExists = `
2
+ if redis.call("EXISTS", KEYS[1]) == 0 then
3
+ redis.call("INCRBY", KEYS[1], ARGV[1])
4
+ redis.call("EXPIRE", KEYS[1], ARGV[2])
5
+ end
6
+
7
+ return redis.call("GET", KEYS[1])
8
+ `;
9
+
10
+ export const IncrByAndEnsureTTLIsSet = `
11
+ local inc = tonumber(ARGV[1])
12
+ local ttl = tonumber(ARGV[2])
13
+
14
+ redis.call("INCRBY", KEYS[1], inc)
15
+
16
+ if redis.call("TTL", KEYS[1]) == -1 then
17
+ redis.call("EXPIRE", KEYS[1], ttl)
18
+ end
19
+
20
+ return tonumber(redis.call("GET", KEYS[1]))
21
+ `;
22
+ export const DecrByAndEnsureTTLIsSet = `
23
+ local inc = tonumber(ARGV[1])
24
+ local ttl = tonumber(ARGV[2])
25
+
26
+ redis.call("DECRBY", KEYS[1], inc)
27
+
28
+ if redis.call("TTL", KEYS[1]) == -1 then
29
+ redis.call("EXPIRE", KEYS[1], ttl)
30
+ end
31
+
32
+ return tonumber(redis.call("GET", KEYS[1]))
33
+ `;
34
+ export const IncrByFloatAndEnsureTTLIsSet = `
35
+ local inc = tonumber(ARGV[1])
36
+ local ttl = tonumber(ARGV[2])
37
+
38
+ redis.call("INCRBYFLOAT", KEYS[1], inc)
39
+
40
+ if redis.call("TTL", KEYS[1]) == -1 then
41
+ redis.call("EXPIRE", KEYS[1], ttl)
42
+ end
43
+
44
+ return tonumber(redis.call("GET", KEYS[1]))
45
+ `;
46
+
47
+ export const IncrByIfExists = `
48
+ if redis.call("EXISTS", KEYS[1]) == 1 then
49
+ redis.call("INCRBY", KEYS[1], ARGV[1])
50
+ end
51
+
52
+ return redis.call("GET", KEYS[1])
53
+ `;
54
+
55
+ export const DecrbyAndSetTTLIfNotExists = `
56
+ if redis.call("EXISTS", KEYS[1]) == 0 then
57
+ redis.call("DECRBY", KEYS[1], ARGV[1])
58
+ redis.call("EXPIRE", KEYS[1], ARGV[2])
59
+ end
60
+
61
+ return redis.call("GET", KEYS[1])
62
+ `;
63
+
64
+ export const DecrbyIfExists = `
65
+ if redis.call("EXISTS", KEYS[1]) == 1 then
66
+ redis.call("DECRBY", KEYS[1], ARGV[1])
67
+ end
68
+
69
+ return redis.call("GET", KEYS[1])
70
+ `;
71
+
72
+ export const IncrByFloatAndSetTTLIfNotExists = `
73
+ if redis.call("EXISTS", KEYS[1]) == 0 then
74
+ redis.call("INCRBYFLOAT", KEYS[1], ARGV[1])
75
+ redis.call("EXPIRE", KEYS[1], ARGV[2])
76
+ end
77
+
78
+ return redis.call("GET", KEYS[1])
79
+ `;
80
+
81
+ export const IncrByFloatIfExists = `
82
+ if redis.call("EXISTS", KEYS[1]) == 1 then
83
+ redis.call("INCRBYFLOAT", KEYS[1], ARGV[1])
84
+ end
85
+
86
+ return redis.call("GET", KEYS[1])
87
+ `;
88
+
89
+ export const RefreshTTLIfBelowThreshold = `
90
+ -- KEYS[1] : key to inspect
91
+ -- ARGV[1] : threshold in seconds (e.g. 10)
92
+ -- ARGV[2] : new TTL in seconds to set (e.g. 60)
93
+
94
+ local ttl = redis.call("TTL", KEYS[1])
95
+
96
+ -- ttl == -2 → key doesn’t exist
97
+ -- ttl == -1 → key has no expiration
98
+ if ttl == -2 then
99
+ return -2 -- key absent
100
+ end
101
+
102
+ local threshold = tonumber(ARGV[1])
103
+ local newTTL = tonumber(ARGV[2])
104
+
105
+ -- If TTL is missing (-1) or below threshold, refresh it
106
+ if ttl == -1 or ttl < threshold then
107
+ redis.call("EXPIRE", KEYS[1], newTTL)
108
+ return newTTL -- return the TTL we just set
109
+ end
110
+
111
+ return ttl -- unchanged TTL
112
+ `;
@@ -0,0 +1,19 @@
1
+ import { ISort, SORT_DIRECTION } from "../interfaces";
2
+
3
+ export const toMongooseSort = (sorts: ISort[]): Record<string, number> => {
4
+ return sorts.reduce((agg, current) => {
5
+ agg[current.columnName] = current.direction === "ASC" ? 1 : -1;
6
+
7
+ return agg;
8
+ }, {});
9
+ };
10
+
11
+ export const toTypeOrmSort = (
12
+ sorts: ISort[]
13
+ ): Record<string, SORT_DIRECTION> => {
14
+ return sorts.reduce((agg, current) => {
15
+ agg[current.columnName] = current.direction;
16
+
17
+ return agg;
18
+ }, {});
19
+ };
@@ -0,0 +1,104 @@
1
+ import { createId } from "@paralleldrive/cuid2";
2
+
3
+ export function generateRandomId(): string {
4
+ return createId();
5
+ }
6
+
7
+ export function generatePassword(length = 16): string {
8
+ const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
9
+ const numbers = "0123456789";
10
+ const symbols = "!@#$%^&*(){}|+-";
11
+ const all = chars + numbers + symbols;
12
+
13
+ let retVal = "";
14
+ retVal += chars.charAt(Math.floor(Math.random() * chars.length));
15
+ retVal += numbers.charAt(Math.floor(Math.random() * numbers.length));
16
+ retVal += symbols.charAt(Math.floor(Math.random() * symbols.length));
17
+
18
+ for (let i = 0; i < length - 3; ++i) {
19
+ retVal += all.charAt(Math.floor(Math.random() * all.length));
20
+ }
21
+ return retVal;
22
+ }
23
+
24
+ function escapeRegexCharacters(str: string): string {
25
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
26
+ }
27
+
28
+ export function validatePasswordStrengthWithMessage(password: string): string {
29
+ const escapedPassword = escapeRegexCharacters(password);
30
+
31
+ if (escapedPassword.length < 8) {
32
+ return "Password must be at least 8 characters long";
33
+ }
34
+ if (!escapedPassword.match(/[a-z]/)) {
35
+ return "Password must contain at least one lowercase letter";
36
+ }
37
+ if (!escapedPassword.match(/[A-Z]/)) {
38
+ return "Password must contain at least one uppercase letter";
39
+ }
40
+ if (!escapedPassword.match(/[0-9]/)) {
41
+ return "Password must contain at least one number";
42
+ }
43
+ if (!escapedPassword.match(/[^a-zA-Z0-9]/)) {
44
+ return "Password must contain at least one special character";
45
+ }
46
+ return "";
47
+ }
48
+
49
+ const standardlize = (f1: string) =>
50
+ f1.replace(new RegExp("_", "g"), "").toLowerCase();
51
+
52
+ type MaskRule = {
53
+ keys: string[];
54
+ pattern: RegExp;
55
+ replacer: (...groups: string[]) => string;
56
+ };
57
+
58
+ const maskRules: MaskRule[] = [
59
+ {
60
+ keys: [
61
+ "password",
62
+ "Authorization",
63
+ "access_token",
64
+ "refresh_token",
65
+ "signature",
66
+ ],
67
+ pattern: /^(.*)$/,
68
+ replacer: () => "***masked***",
69
+ },
70
+ {
71
+ keys: ["txid", "txnid"],
72
+ pattern: /^(.{10})(.*)(.{36})$/,
73
+ replacer: (_match, prefix, middle, suffix) =>
74
+ `${prefix}${"*".repeat(middle.length)}${suffix}`,
75
+ },
76
+ ];
77
+
78
+ export const maskFn = (
79
+ key: string,
80
+ value: unknown,
81
+ additionalMaskRules: MaskRule[] = []
82
+ ): unknown => {
83
+ // Only process string values
84
+ if (typeof value !== "string") {
85
+ return value;
86
+ }
87
+
88
+ const normalizedKey = standardlize(key);
89
+ // Merge default rules with any additional ones
90
+ const allRules = [...maskRules, ...additionalMaskRules];
91
+
92
+ // Find a rule whose keys match the normalized key
93
+ const rule = allRules.find(({ keys }) =>
94
+ keys.some((k) => standardlize(k) === normalizedKey)
95
+ );
96
+
97
+ // No matching rule? Return the original value
98
+ if (!rule) {
99
+ return value;
100
+ }
101
+
102
+ // Apply pattern and replacer
103
+ return value.replace(rule.pattern, rule.replacer);
104
+ };
@@ -0,0 +1,25 @@
1
+ import { TaskFn } from "../interfaces";
2
+
3
+ export async function runWithTimeout<T = any>(
4
+ handler: TaskFn,
5
+ timeoutInMs: number
6
+ ): Promise<T> {
7
+ return new Promise((resolve, reject) => {
8
+ const timeout = setTimeout(
9
+ () => reject(new Error("task timed out")),
10
+ timeoutInMs
11
+ );
12
+
13
+ handler()
14
+ .then((result: T) => {
15
+ clearTimeout(timeout);
16
+
17
+ resolve(result);
18
+ })
19
+ .catch((error: Error) => {
20
+ clearTimeout(timeout);
21
+
22
+ reject(error);
23
+ });
24
+ });
25
+ }
@@ -0,0 +1,146 @@
1
+ // test/normalizePairName.spec.ts
2
+ import { describe, it } from "mocha";
3
+ import { expect } from "chai";
4
+ import { normalizePairName } from "./trading-pair-helper";
5
+ import { CRYPTO_TOKEN, STABLE_COIN } from "../constants";
6
+
7
+ describe("normalizePairName (functional factory)", () => {
8
+ const normalize = normalizePairName(STABLE_COIN, CRYPTO_TOKEN);
9
+
10
+ it("places stable coin last when stableCoinRule = 'last' (order-agnostic input)", () => {
11
+ const a = normalize("USDTWVPC", {
12
+ stableCoinRule: "last",
13
+ sortOrder: "asc",
14
+ separator: "/",
15
+ outputFormater: undefined as any,
16
+ });
17
+ const b = normalize("WVPCUSDT", {
18
+ stableCoinRule: "last",
19
+ sortOrder: "asc",
20
+ separator: "/",
21
+ outputFormater: undefined as any,
22
+ });
23
+ expect(a).to.equal("wvpc/usdt");
24
+ expect(b).to.equal("wvpc/usdt");
25
+ });
26
+
27
+ it("places stable coin first when stableCoinRule = 'first'", () => {
28
+ const out = normalize("WVPCUSDC", {
29
+ stableCoinRule: "first",
30
+ sortOrder: "asc",
31
+ separator: "/",
32
+ outputFormater: undefined as any,
33
+ });
34
+ expect(out).to.equal("usdc/wvpc");
35
+ });
36
+
37
+ it("with stableCoinRule = 'default', uses general sort (no special placement)", () => {
38
+ const outAsc = normalize("WVPCUSDT", {
39
+ stableCoinRule: "default",
40
+ sortOrder: "asc",
41
+ separator: "/",
42
+ outputFormater: undefined as any,
43
+ });
44
+ const outDesc = normalize("WVPCUSDT", {
45
+ stableCoinRule: "default",
46
+ sortOrder: "desc",
47
+ separator: "/",
48
+ outputFormater: undefined as any,
49
+ });
50
+ // asc: 'usdt' < 'wvpc' lexicographically
51
+ expect(outAsc).to.equal("usdt/wvpc");
52
+ // desc: 'wvpc' > 'usdt'
53
+ expect(outDesc).to.equal("wvpc/usdt");
54
+ });
55
+
56
+ it("strips separators and is case-insensitive", () => {
57
+ const a = normalize("ETH/USDT", {
58
+ stableCoinRule: "last",
59
+ sortOrder: "asc",
60
+ separator: "/",
61
+ outputFormater: undefined as any,
62
+ });
63
+ const b = normalize("ETH|USDT", {
64
+ stableCoinRule: "last",
65
+ sortOrder: "asc",
66
+ separator: "/",
67
+ outputFormater: undefined as any,
68
+ });
69
+ const c = normalize("wVpCusdT", {
70
+ stableCoinRule: "last",
71
+ sortOrder: "asc",
72
+ separator: "/",
73
+ outputFormater: undefined as any,
74
+ });
75
+ expect(a).to.equal("eth/usdt");
76
+ expect(b).to.equal("eth/usdt");
77
+ expect(c).to.equal("wvpc/usdt");
78
+ });
79
+
80
+ it("handles overlapping tokens by preferring longest match (e.g., WETH vs ETH)", () => {
81
+ // No stable coin here, so general path + sorting
82
+ const outAsc = normalize("WETHETH", {
83
+ stableCoinRule: "default",
84
+ sortOrder: "asc",
85
+ separator: "/",
86
+ outputFormater: undefined as any,
87
+ });
88
+ const outDesc = normalize("WETHETH", {
89
+ stableCoinRule: "default",
90
+ sortOrder: "desc",
91
+ separator: "/",
92
+ outputFormater: undefined as any,
93
+ });
94
+ // After longest-first split → parts = ['weth','eth']; then sorted:
95
+ expect(outAsc).to.equal("eth/weth");
96
+ expect(outDesc).to.equal("weth/eth");
97
+ });
98
+
99
+ it("sorts non-stable pairs lexicographically based on sortOrder", () => {
100
+ const outAsc = normalize("BTCETH", {
101
+ stableCoinRule: "default",
102
+ sortOrder: "asc",
103
+ separator: "/",
104
+ outputFormater: undefined as any,
105
+ });
106
+ const outDesc = normalize("BTCETH", {
107
+ stableCoinRule: "default",
108
+ sortOrder: "desc",
109
+ separator: "/",
110
+ outputFormater: undefined as any,
111
+ });
112
+ expect(outAsc).to.equal("btc/eth");
113
+ expect(outDesc).to.equal("eth/btc");
114
+ });
115
+
116
+ it("passes the separator into the output formatter", () => {
117
+ const out = normalize("WVPCUSDT", {
118
+ stableCoinRule: "last",
119
+ sortOrder: "asc",
120
+ separator: "-",
121
+ outputFormater: (parts, sep) => parts.join(sep),
122
+ });
123
+ expect(out).to.equal("wvpc-usdt");
124
+ });
125
+
126
+ it("supports custom formatter (e.g., uppercase concatenation)", () => {
127
+ const out = normalize("WVPCUSDT", {
128
+ stableCoinRule: "last",
129
+ sortOrder: "asc",
130
+ separator: "/",
131
+ outputFormater: (parts) => parts.map((p) => p.toUpperCase()).join(""),
132
+ });
133
+ expect(out).to.equal("WVPCUSDT");
134
+ });
135
+
136
+ it("throws when no known tokens found", () => {
137
+ expect(() =>
138
+ normalize("FOOBAR", {
139
+ stableCoinRule: "default",
140
+ sortOrder: "asc",
141
+ separator: "/",
142
+ outputFormater: undefined as any,
143
+ })
144
+ ).to.throw(/does not contain crypto from list/i);
145
+ });
146
+ });
@@ -0,0 +1,78 @@
1
+ import { CRYPTO_TOKEN, STABLE_COIN } from "../constants";
2
+
3
+ const esc = (s: string) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
4
+
5
+ export type PairNameFormater = (data: string[], separator: string) => string;
6
+
7
+ const defaultFormatter: PairNameFormater = (data, separator) =>
8
+ data.join(separator);
9
+
10
+ export type NormalizePairNameOptions = {
11
+ sortOrder?: "asc" | "desc";
12
+ stableCoinRule?: "first" | "last" | "default";
13
+ separator?: string;
14
+ outputFormater?: PairNameFormater;
15
+ };
16
+
17
+ export const normalizePairName = (
18
+ stableCoinList = STABLE_COIN,
19
+ cryptoList = CRYPTO_TOKEN
20
+ ) => {
21
+ const stableTokensLower = Object.values(stableCoinList).map((i) =>
22
+ i.toLowerCase()
23
+ );
24
+ const stableRe = new RegExp(`(${stableTokensLower.map(esc).join("|")})`, "i");
25
+
26
+ // Keep both raw-lower (for includes) and escaped (for regex)
27
+ const cryptoTokensLower = Object.values(cryptoList)
28
+ .map((i) => i.toLowerCase())
29
+ .sort((a, b) => b.length - a.length); // longest-first to avoid overlaps
30
+
31
+ const cryptoTokensEscaped = cryptoTokensLower.map(esc);
32
+
33
+ return (pairName: string, options?: NormalizePairNameOptions): string => {
34
+ const {
35
+ outputFormater = defaultFormatter,
36
+ sortOrder = "asc",
37
+ stableCoinRule = "last",
38
+ separator = "/",
39
+ } = options || {};
40
+
41
+ // strip separators and normalize case once
42
+ const normalized = pairName.replace(/[|/]/g, "").toLowerCase();
43
+ const parts: string[] = [];
44
+
45
+ // Stable-coin rule branch
46
+ const hasStable = stableTokensLower.some((t) => normalized.includes(t));
47
+ if (stableCoinRule !== "default" && hasStable) {
48
+ const other = normalized.replace(stableRe, ""); // remove first stable
49
+ const stable = normalized.replace(other, ""); // remainder is the stable
50
+ const ordered =
51
+ stableCoinRule === "first" ? [stable, other] : [other, stable];
52
+
53
+ return outputFormater(ordered, separator);
54
+ }
55
+
56
+ // General branch
57
+ for (let i = 0; i < cryptoTokensLower.length; i++) {
58
+ const raw = cryptoTokensLower[i];
59
+ if (normalized.includes(raw)) {
60
+ const pat = new RegExp(cryptoTokensEscaped[i], "i");
61
+ const remainder = normalized.replace(pat, "");
62
+ parts.push(raw, remainder);
63
+ break; // stop at first/best match
64
+ }
65
+ }
66
+
67
+ if (parts.length === 0) {
68
+ throw new Error("pairname does not contain crypto from list");
69
+ }
70
+
71
+ const ordered =
72
+ sortOrder === "asc"
73
+ ? parts.sort((a, b) => a.localeCompare(b))
74
+ : parts.sort((a, b) => b.localeCompare(a));
75
+
76
+ return outputFormater(ordered, separator);
77
+ };
78
+ };