@moxon/api 6.0.0-pre

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 (246) hide show
  1. package/.prettierignore +5 -0
  2. package/LICENSE +28 -0
  3. package/README.md +277 -0
  4. package/dist/app.d.ts +2 -0
  5. package/dist/app.js +55 -0
  6. package/dist/app.js.map +1 -0
  7. package/dist/config/env.d.ts +22 -0
  8. package/dist/config/env.js +36 -0
  9. package/dist/config/env.js.map +1 -0
  10. package/dist/config/plans.d.ts +26 -0
  11. package/dist/config/plans.js +44 -0
  12. package/dist/config/plans.js.map +1 -0
  13. package/dist/config/versions.d.ts +18 -0
  14. package/dist/config/versions.js +248 -0
  15. package/dist/config/versions.js.map +1 -0
  16. package/dist/constants.d.ts +48 -0
  17. package/dist/constants.js +75 -0
  18. package/dist/constants.js.map +1 -0
  19. package/dist/middleware/cors.d.ts +2 -0
  20. package/dist/middleware/cors.js +31 -0
  21. package/dist/middleware/cors.js.map +1 -0
  22. package/dist/middleware/error.d.ts +4 -0
  23. package/dist/middleware/error.js +8 -0
  24. package/dist/middleware/error.js.map +1 -0
  25. package/dist/middleware/json.d.ts +2 -0
  26. package/dist/middleware/json.js +8 -0
  27. package/dist/middleware/json.js.map +1 -0
  28. package/dist/middleware/logger.d.ts +26 -0
  29. package/dist/middleware/logger.js +65 -0
  30. package/dist/middleware/logger.js.map +1 -0
  31. package/dist/middleware/ratelimit.d.ts +2 -0
  32. package/dist/middleware/ratelimit.js +83 -0
  33. package/dist/middleware/ratelimit.js.map +1 -0
  34. package/dist/middleware/version.d.ts +3 -0
  35. package/dist/middleware/version.js +30 -0
  36. package/dist/middleware/version.js.map +1 -0
  37. package/dist/modules/v4/address.d.ts +20 -0
  38. package/dist/modules/v4/address.js +381 -0
  39. package/dist/modules/v4/address.js.map +1 -0
  40. package/dist/modules/v4/agent.d.ts +30 -0
  41. package/dist/modules/v4/agent.js +92 -0
  42. package/dist/modules/v4/agent.js.map +1 -0
  43. package/dist/modules/v4/algorithms.d.ts +90 -0
  44. package/dist/modules/v4/algorithms.js +279 -0
  45. package/dist/modules/v4/algorithms.js.map +1 -0
  46. package/dist/modules/v4/avatar.d.ts +23 -0
  47. package/dist/modules/v4/avatar.js +136 -0
  48. package/dist/modules/v4/avatar.js.map +1 -0
  49. package/dist/modules/v4/barcode.d.ts +27 -0
  50. package/dist/modules/v4/barcode.js +440 -0
  51. package/dist/modules/v4/barcode.js.map +1 -0
  52. package/dist/modules/v4/captcha.d.ts +22 -0
  53. package/dist/modules/v4/captcha.js +79 -0
  54. package/dist/modules/v4/captcha.js.map +1 -0
  55. package/dist/modules/v4/chat.d.ts +21 -0
  56. package/dist/modules/v4/chat.js +100 -0
  57. package/dist/modules/v4/chat.js.map +1 -0
  58. package/dist/modules/v4/color.d.ts +16 -0
  59. package/dist/modules/v4/color.js +59 -0
  60. package/dist/modules/v4/color.js.map +1 -0
  61. package/dist/modules/v4/convert.d.ts +15 -0
  62. package/dist/modules/v4/convert.js +116 -0
  63. package/dist/modules/v4/convert.js.map +1 -0
  64. package/dist/modules/v4/credit.d.ts +22 -0
  65. package/dist/modules/v4/credit.js +104 -0
  66. package/dist/modules/v4/credit.js.map +1 -0
  67. package/dist/modules/v4/cron.d.ts +17 -0
  68. package/dist/modules/v4/cron.js +202 -0
  69. package/dist/modules/v4/cron.js.map +1 -0
  70. package/dist/modules/v4/dice.d.ts +16 -0
  71. package/dist/modules/v4/dice.js +37 -0
  72. package/dist/modules/v4/dice.js.map +1 -0
  73. package/dist/modules/v4/domain.d.ts +6 -0
  74. package/dist/modules/v4/domain.js +83 -0
  75. package/dist/modules/v4/domain.js.map +1 -0
  76. package/dist/modules/v4/encode.d.ts +81 -0
  77. package/dist/modules/v4/encode.js +236 -0
  78. package/dist/modules/v4/encode.js.map +1 -0
  79. package/dist/modules/v4/geo.d.ts +30 -0
  80. package/dist/modules/v4/geo.js +51 -0
  81. package/dist/modules/v4/geo.js.map +1 -0
  82. package/dist/modules/v4/hash.d.ts +15 -0
  83. package/dist/modules/v4/hash.js +25 -0
  84. package/dist/modules/v4/hash.js.map +1 -0
  85. package/dist/modules/v4/hyperplanning.d.ts +19 -0
  86. package/dist/modules/v4/hyperplanning.js +80 -0
  87. package/dist/modules/v4/hyperplanning.js.map +1 -0
  88. package/dist/modules/v4/ip.d.ts +19 -0
  89. package/dist/modules/v4/ip.js +132 -0
  90. package/dist/modules/v4/ip.js.map +1 -0
  91. package/dist/modules/v4/levenshtein.d.ts +13 -0
  92. package/dist/modules/v4/levenshtein.js +37 -0
  93. package/dist/modules/v4/levenshtein.js.map +1 -0
  94. package/dist/modules/v4/palette.d.ts +19 -0
  95. package/dist/modules/v4/palette.js +56 -0
  96. package/dist/modules/v4/palette.js.map +1 -0
  97. package/dist/modules/v4/password.d.ts +25 -0
  98. package/dist/modules/v4/password.js +343 -0
  99. package/dist/modules/v4/password.js.map +1 -0
  100. package/dist/modules/v4/personal.d.ts +6 -0
  101. package/dist/modules/v4/personal.js +121 -0
  102. package/dist/modules/v4/personal.js.map +1 -0
  103. package/dist/modules/v4/placeholder.d.ts +30 -0
  104. package/dist/modules/v4/placeholder.js +160 -0
  105. package/dist/modules/v4/placeholder.js.map +1 -0
  106. package/dist/modules/v4/qrcode.d.ts +25 -0
  107. package/dist/modules/v4/qrcode.js +92 -0
  108. package/dist/modules/v4/qrcode.js.map +1 -0
  109. package/dist/modules/v4/regex.d.ts +23 -0
  110. package/dist/modules/v4/regex.js +48 -0
  111. package/dist/modules/v4/regex.js.map +1 -0
  112. package/dist/modules/v4/statistics.d.ts +20 -0
  113. package/dist/modules/v4/statistics.js +48 -0
  114. package/dist/modules/v4/statistics.js.map +1 -0
  115. package/dist/modules/v4/text.d.ts +43 -0
  116. package/dist/modules/v4/text.js +323 -0
  117. package/dist/modules/v4/text.js.map +1 -0
  118. package/dist/modules/v4/tic_tac_toe.d.ts +19 -0
  119. package/dist/modules/v4/tic_tac_toe.js +214 -0
  120. package/dist/modules/v4/tic_tac_toe.js.map +1 -0
  121. package/dist/modules/v4/time.d.ts +15 -0
  122. package/dist/modules/v4/time.js +124 -0
  123. package/dist/modules/v4/time.js.map +1 -0
  124. package/dist/modules/v4/token.d.ts +9 -0
  125. package/dist/modules/v4/token.js +45 -0
  126. package/dist/modules/v4/token.js.map +1 -0
  127. package/dist/modules/v4/username.d.ts +6 -0
  128. package/dist/modules/v4/username.js +92 -0
  129. package/dist/modules/v4/username.js.map +1 -0
  130. package/dist/modules/v4/validate.d.ts +34 -0
  131. package/dist/modules/v4/validate.js +75 -0
  132. package/dist/modules/v4/validate.js.map +1 -0
  133. package/dist/modules/v4.d.ts +32 -0
  134. package/dist/modules/v4.js +33 -0
  135. package/dist/modules/v4.js.map +1 -0
  136. package/dist/modules/v5/address.d.ts +5 -0
  137. package/dist/modules/v5/address.js +20 -0
  138. package/dist/modules/v5/address.js.map +1 -0
  139. package/dist/modules/v5/algorithms.d.ts +9 -0
  140. package/dist/modules/v5/algorithms.js +39 -0
  141. package/dist/modules/v5/algorithms.js.map +1 -0
  142. package/dist/modules/v5/asymmetric.d.ts +26 -0
  143. package/dist/modules/v5/asymmetric.js +74 -0
  144. package/dist/modules/v5/asymmetric.js.map +1 -0
  145. package/dist/modules/v5/barcode.d.ts +27 -0
  146. package/dist/modules/v5/barcode.js +424 -0
  147. package/dist/modules/v5/barcode.js.map +1 -0
  148. package/dist/modules/v5/base.d.ts +16 -0
  149. package/dist/modules/v5/base.js +41 -0
  150. package/dist/modules/v5/base.js.map +1 -0
  151. package/dist/modules/v5/captcha.d.ts +27 -0
  152. package/dist/modules/v5/captcha.js +136 -0
  153. package/dist/modules/v5/captcha.js.map +1 -0
  154. package/dist/modules/v5/case.d.ts +10 -0
  155. package/dist/modules/v5/case.js +57 -0
  156. package/dist/modules/v5/case.js.map +1 -0
  157. package/dist/modules/v5/chart.d.ts +53 -0
  158. package/dist/modules/v5/chart.js +385 -0
  159. package/dist/modules/v5/chart.js.map +1 -0
  160. package/dist/modules/v5/chat.d.ts +21 -0
  161. package/dist/modules/v5/chat.js +107 -0
  162. package/dist/modules/v5/chat.js.map +1 -0
  163. package/dist/modules/v5/csv.d.ts +29 -0
  164. package/dist/modules/v5/csv.js +143 -0
  165. package/dist/modules/v5/csv.js.map +1 -0
  166. package/dist/modules/v5/diff.d.ts +20 -0
  167. package/dist/modules/v5/diff.js +81 -0
  168. package/dist/modules/v5/diff.js.map +1 -0
  169. package/dist/modules/v5/evaluate.d.ts +14 -0
  170. package/dist/modules/v5/evaluate.js +284 -0
  171. package/dist/modules/v5/evaluate.js.map +1 -0
  172. package/dist/modules/v5/jwt.d.ts +11 -0
  173. package/dist/modules/v5/jwt.js +42 -0
  174. package/dist/modules/v5/jwt.js.map +1 -0
  175. package/dist/modules/v5/matrix.d.ts +77 -0
  176. package/dist/modules/v5/matrix.js +239 -0
  177. package/dist/modules/v5/matrix.js.map +1 -0
  178. package/dist/modules/v5/otp.d.ts +30 -0
  179. package/dist/modules/v5/otp.js +117 -0
  180. package/dist/modules/v5/otp.js.map +1 -0
  181. package/dist/modules/v5/pow.d.ts +29 -0
  182. package/dist/modules/v5/pow.js +49 -0
  183. package/dist/modules/v5/pow.js.map +1 -0
  184. package/dist/modules/v5/read.d.ts +20 -0
  185. package/dist/modules/v5/read.js +59 -0
  186. package/dist/modules/v5/read.js.map +1 -0
  187. package/dist/modules/v5/semver.d.ts +33 -0
  188. package/dist/modules/v5/semver.js +99 -0
  189. package/dist/modules/v5/semver.js.map +1 -0
  190. package/dist/modules/v5/symmetric.d.ts +15 -0
  191. package/dist/modules/v5/symmetric.js +88 -0
  192. package/dist/modules/v5/symmetric.js.map +1 -0
  193. package/dist/modules/v5/text.d.ts +5 -0
  194. package/dist/modules/v5/text.js +12 -0
  195. package/dist/modules/v5/text.js.map +1 -0
  196. package/dist/modules/v5/tic_tac_toe.d.ts +19 -0
  197. package/dist/modules/v5/tic_tac_toe.js +226 -0
  198. package/dist/modules/v5/tic_tac_toe.js.map +1 -0
  199. package/dist/modules/v5/url.d.ts +18 -0
  200. package/dist/modules/v5/url.js +51 -0
  201. package/dist/modules/v5/url.js.map +1 -0
  202. package/dist/modules/v5/uuid.d.ts +25 -0
  203. package/dist/modules/v5/uuid.js +40 -0
  204. package/dist/modules/v5/uuid.js.map +1 -0
  205. package/dist/modules/v5.d.ts +24 -0
  206. package/dist/modules/v5.js +25 -0
  207. package/dist/modules/v5.js.map +1 -0
  208. package/dist/modules/v6.d.ts +1 -0
  209. package/dist/modules/v6.js +2 -0
  210. package/dist/modules/v6.js.map +1 -0
  211. package/dist/routes/delete.d.ts +2 -0
  212. package/dist/routes/delete.js +73 -0
  213. package/dist/routes/delete.js.map +1 -0
  214. package/dist/routes/get.d.ts +2 -0
  215. package/dist/routes/get.js +857 -0
  216. package/dist/routes/get.js.map +1 -0
  217. package/dist/routes/index.d.ts +2 -0
  218. package/dist/routes/index.js +95 -0
  219. package/dist/routes/index.js.map +1 -0
  220. package/dist/routes/patch.d.ts +2 -0
  221. package/dist/routes/patch.js +45 -0
  222. package/dist/routes/patch.js.map +1 -0
  223. package/dist/routes/post.d.ts +2 -0
  224. package/dist/routes/post.js +604 -0
  225. package/dist/routes/post.js.map +1 -0
  226. package/dist/storage/index.d.ts +5 -0
  227. package/dist/storage/index.js +14 -0
  228. package/dist/storage/index.js.map +1 -0
  229. package/dist/types/storage.d.ts +52 -0
  230. package/dist/types/storage.js +2 -0
  231. package/dist/types/storage.js.map +1 -0
  232. package/dist/utils/challenge.d.ts +40 -0
  233. package/dist/utils/challenge.js +75 -0
  234. package/dist/utils/challenge.js.map +1 -0
  235. package/dist/utils/colors.d.ts +44 -0
  236. package/dist/utils/colors.js +93 -0
  237. package/dist/utils/colors.js.map +1 -0
  238. package/dist/utils/helpers.d.ts +55 -0
  239. package/dist/utils/helpers.js +82 -0
  240. package/dist/utils/helpers.js.map +1 -0
  241. package/dist/utils/response.d.ts +9 -0
  242. package/dist/utils/response.js +24 -0
  243. package/dist/utils/response.js.map +1 -0
  244. package/package.json +90 -0
  245. package/robots.txt +74 -0
  246. package/src/favicon.ico +0 -0
@@ -0,0 +1,52 @@
1
+ export interface LogEntry {
2
+ timestamp: string;
3
+ method: string;
4
+ url: string;
5
+ status: number;
6
+ duration: string;
7
+ platform: string | undefined;
8
+ }
9
+ export interface ChatMessage {
10
+ username: string;
11
+ message: string;
12
+ timestamp: string;
13
+ }
14
+ export interface ChatStorage {
15
+ messages: ChatMessage[];
16
+ privateChats: Record<string, ChatMessage[]>;
17
+ sessions: Record<string, {
18
+ user: string;
19
+ last: number;
20
+ }>;
21
+ rateLimits: Record<string, number[]>;
22
+ }
23
+ export interface TicTacToeMove {
24
+ username: string;
25
+ move: string;
26
+ session: string;
27
+ }
28
+ export interface TicTacToeGame {
29
+ moves: TicTacToeMove[];
30
+ players: string[];
31
+ private: boolean;
32
+ creation: number;
33
+ last?: number;
34
+ }
35
+ export interface TicTacToeStorage {
36
+ games: Record<string, TicTacToeGame>;
37
+ sessions: Record<string, {
38
+ user: string;
39
+ last: number;
40
+ }>;
41
+ rateLimits: Record<string, number[]>;
42
+ }
43
+ export interface ChallengeStorage {
44
+ usedNonces: Map<string, number>;
45
+ }
46
+ export interface IpLimits {
47
+ [ip: string]: {
48
+ [hour: string]: {
49
+ [minute: string]: number;
50
+ };
51
+ };
52
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/types/storage.ts"],"names":[],"mappings":""}
@@ -0,0 +1,40 @@
1
+ import type { ChallengeStorage } from '../types/storage.js';
2
+ export interface ChallengeVerification {
3
+ valid: boolean;
4
+ reason?: 'wrong' | 'expired' | 'used' | 'invalid';
5
+ }
6
+ export interface TokenPayload {
7
+ type: 'img' | 'pow';
8
+ nonce: string;
9
+ exp: number;
10
+ salt?: string;
11
+ difficulty?: number;
12
+ sig: string;
13
+ }
14
+ /**
15
+ * Signs a challenge into a stateless token. The expected answer never appears in
16
+ * the token itself, only in the HMAC, so it cannot be read back by the client.
17
+ *
18
+ * @param type - Challenge kind: img for a captcha, pow for a proof-of-work
19
+ * @param payload - Secret material bound to the token: the answer, or the salt and difficulty
20
+ * @param extra - Public fields to carry along, such as salt and difficulty
21
+ * @returns Base64url token carrying the nonce, expiry and signature
22
+ */
23
+ export declare function signToken(type: 'img' | 'pow', payload: string, extra?: Record<string, unknown>): string;
24
+ /**
25
+ * Verifies a token against the payload it was signed with, then consumes its
26
+ * nonce so the same token cannot be replayed.
27
+ *
28
+ * @param token - Token issued by signToken
29
+ * @param payload - Payload to check the signature against
30
+ * @param storage - Store of already consumed nonces
31
+ * @returns Verification result, with a reason when it fails
32
+ */
33
+ export declare function verifyToken(token: string, payload: string, storage: ChallengeStorage): ChallengeVerification;
34
+ /**
35
+ * Reads the public fields of a token without verifying its signature.
36
+ *
37
+ * @param token - Token issued by signToken
38
+ * @returns Decoded payload, or null if the token is malformed
39
+ */
40
+ export declare function readToken(token: string): TokenPayload | null;
@@ -0,0 +1,75 @@
1
+ import { createHmac, randomBytes, timingSafeEqual } from 'node:crypto';
2
+ import { env } from '../config/env.js';
3
+ import { CHALLENGE_TTL } from '../constants.js';
4
+ const secret = env.CHALLENGE_SECRET || randomBytes(32).toString('hex');
5
+ const sign = (type, nonce, exp, payload) => createHmac('sha256', secret).update(`${type}.${nonce}.${exp}.${payload}`).digest('hex');
6
+ function decode(token) {
7
+ try {
8
+ const parsed = JSON.parse(Buffer.from(token, 'base64url').toString('utf8'));
9
+ if (typeof parsed.nonce !== 'string' || typeof parsed.exp !== 'number' || typeof parsed.sig !== 'string') {
10
+ return null;
11
+ }
12
+ return parsed;
13
+ }
14
+ catch {
15
+ return null;
16
+ }
17
+ }
18
+ function prune(storage, now) {
19
+ for (const [nonce, exp] of storage.usedNonces) {
20
+ if (exp <= now)
21
+ storage.usedNonces.delete(nonce);
22
+ }
23
+ }
24
+ /**
25
+ * Signs a challenge into a stateless token. The expected answer never appears in
26
+ * the token itself, only in the HMAC, so it cannot be read back by the client.
27
+ *
28
+ * @param type - Challenge kind: img for a captcha, pow for a proof-of-work
29
+ * @param payload - Secret material bound to the token: the answer, or the salt and difficulty
30
+ * @param extra - Public fields to carry along, such as salt and difficulty
31
+ * @returns Base64url token carrying the nonce, expiry and signature
32
+ */
33
+ export function signToken(type, payload, extra = {}) {
34
+ const nonce = randomBytes(16).toString('hex');
35
+ const exp = Date.now() + CHALLENGE_TTL;
36
+ const body = { type, nonce, exp, ...extra, sig: sign(type, nonce, exp, payload) };
37
+ return Buffer.from(JSON.stringify(body)).toString('base64url');
38
+ }
39
+ /**
40
+ * Verifies a token against the payload it was signed with, then consumes its
41
+ * nonce so the same token cannot be replayed.
42
+ *
43
+ * @param token - Token issued by signToken
44
+ * @param payload - Payload to check the signature against
45
+ * @param storage - Store of already consumed nonces
46
+ * @returns Verification result, with a reason when it fails
47
+ */
48
+ export function verifyToken(token, payload, storage) {
49
+ const decoded = decode(token);
50
+ if (!decoded)
51
+ return { valid: false, reason: 'invalid' };
52
+ const now = Date.now();
53
+ prune(storage, now);
54
+ if (decoded.exp <= now)
55
+ return { valid: false, reason: 'expired' };
56
+ if (storage.usedNonces.has(decoded.nonce))
57
+ return { valid: false, reason: 'used' };
58
+ const expected = Buffer.from(sign(decoded.type, decoded.nonce, decoded.exp, payload), 'hex');
59
+ const actual = Buffer.from(decoded.sig, 'hex');
60
+ if (expected.length !== actual.length || !timingSafeEqual(expected, actual)) {
61
+ return { valid: false, reason: 'wrong' };
62
+ }
63
+ storage.usedNonces.set(decoded.nonce, decoded.exp);
64
+ return { valid: true };
65
+ }
66
+ /**
67
+ * Reads the public fields of a token without verifying its signature.
68
+ *
69
+ * @param token - Token issued by signToken
70
+ * @returns Decoded payload, or null if the token is malformed
71
+ */
72
+ export function readToken(token) {
73
+ return decode(token);
74
+ }
75
+ //# sourceMappingURL=challenge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"challenge.js","sourceRoot":"","sources":["../../src/utils/challenge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Parses a hex color string into an RGB tuple.
3
+ *
4
+ * @param hex - Hex color string (#RRGGBB or RRGGBB)
5
+ * @returns RGB tuple [r, g, b] with values 0-255
6
+ * @throws Error if the hex string is invalid
7
+ */
8
+ export declare function hexToRgb(hex: string): [number, number, number];
9
+ /**
10
+ * Converts HSL values to an RGB tuple.
11
+ *
12
+ * @param h - Hue in degrees (0-360)
13
+ * @param s - Saturation (0-1)
14
+ * @param l - Lightness (0-1)
15
+ * @returns RGB tuple [r, g, b] with values 0-255
16
+ */
17
+ export declare function hslToRgb(h: number, s: number, l: number): [number, number, number];
18
+ /**
19
+ * Validates and normalizes a hex color string, adding # if missing.
20
+ *
21
+ * @param value - Raw color value (with or without #)
22
+ * @param def - Default color if value is empty
23
+ * @returns Normalized hex color string with #
24
+ * @throws Error if the color format is invalid
25
+ */
26
+ export declare function normalizeColor(value: string | undefined, def: string): string;
27
+ /**
28
+ * Formats an RGB tuple as a hex color string.
29
+ *
30
+ * @param r - Red channel (0-255)
31
+ * @param g - Green channel (0-255)
32
+ * @param b - Blue channel (0-255)
33
+ * @returns Hex color string (#rrggbb)
34
+ */
35
+ export declare function rgbToHex(r: number, g: number, b: number): string;
36
+ /**
37
+ * Converts RGB values to an HSL tuple.
38
+ *
39
+ * @param r - Red channel (0-255)
40
+ * @param g - Green channel (0-255)
41
+ * @param b - Blue channel (0-255)
42
+ * @returns HSL tuple [h (0-360), s (0-1), l (0-1)]
43
+ */
44
+ export declare function rgbToHsl(r: number, g: number, b: number): [number, number, number];
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Parses a hex color string into an RGB tuple.
3
+ *
4
+ * @param hex - Hex color string (#RRGGBB or RRGGBB)
5
+ * @returns RGB tuple [r, g, b] with values 0-255
6
+ * @throws Error if the hex string is invalid
7
+ */
8
+ export function hexToRgb(hex) {
9
+ const clean = hex.replace('#', '');
10
+ if (!/^[0-9a-fA-F]{6}$/.test(clean))
11
+ throw new Error('Invalid HEX color (use #RRGGBB)');
12
+ return [parseInt(clean.slice(0, 2), 16), parseInt(clean.slice(2, 4), 16), parseInt(clean.slice(4, 6), 16)];
13
+ }
14
+ /**
15
+ * Converts HSL values to an RGB tuple.
16
+ *
17
+ * @param h - Hue in degrees (0-360)
18
+ * @param s - Saturation (0-1)
19
+ * @param l - Lightness (0-1)
20
+ * @returns RGB tuple [r, g, b] with values 0-255
21
+ */
22
+ export function hslToRgb(h, s, l) {
23
+ const c = (1 - Math.abs(2 * l - 1)) * s;
24
+ const x = c * (1 - Math.abs(((h / 60) % 2) - 1));
25
+ const m = l - c / 2;
26
+ let r1 = 0, g1 = 0, b1 = 0;
27
+ if (h < 60)
28
+ [r1, g1, b1] = [c, x, 0];
29
+ else if (h < 120)
30
+ [r1, g1, b1] = [x, c, 0];
31
+ else if (h < 180)
32
+ [r1, g1, b1] = [0, c, x];
33
+ else if (h < 240)
34
+ [r1, g1, b1] = [0, x, c];
35
+ else if (h < 300)
36
+ [r1, g1, b1] = [x, 0, c];
37
+ else
38
+ [r1, g1, b1] = [c, 0, x];
39
+ return [Math.round((r1 + m) * 255), Math.round((g1 + m) * 255), Math.round((b1 + m) * 255)];
40
+ }
41
+ /**
42
+ * Validates and normalizes a hex color string, adding # if missing.
43
+ *
44
+ * @param value - Raw color value (with or without #)
45
+ * @param def - Default color if value is empty
46
+ * @returns Normalized hex color string with #
47
+ * @throws Error if the color format is invalid
48
+ */
49
+ export function normalizeColor(value, def) {
50
+ if (!value)
51
+ return def;
52
+ const clean = value.startsWith('#') ? value : `#${value}`;
53
+ if (!/^#([0-9a-fA-F]{3}){1,2}$/.test(clean))
54
+ throw new Error('Invalid color (use hex like ff6600)');
55
+ return clean;
56
+ }
57
+ /**
58
+ * Formats an RGB tuple as a hex color string.
59
+ *
60
+ * @param r - Red channel (0-255)
61
+ * @param g - Green channel (0-255)
62
+ * @param b - Blue channel (0-255)
63
+ * @returns Hex color string (#rrggbb)
64
+ */
65
+ export function rgbToHex(r, g, b) {
66
+ return `#${[r, g, b].map((x) => x.toString(16).padStart(2, '0')).join('')}`;
67
+ }
68
+ /**
69
+ * Converts RGB values to an HSL tuple.
70
+ *
71
+ * @param r - Red channel (0-255)
72
+ * @param g - Green channel (0-255)
73
+ * @param b - Blue channel (0-255)
74
+ * @returns HSL tuple [h (0-360), s (0-1), l (0-1)]
75
+ */
76
+ export function rgbToHsl(r, g, b) {
77
+ const r1 = r / 255, g1 = g / 255, b1 = b / 255;
78
+ const max = Math.max(r1, g1, b1), min = Math.min(r1, g1, b1);
79
+ const l = (max + min) / 2;
80
+ if (max === min)
81
+ return [0, 0, l];
82
+ const d = max - min;
83
+ const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
84
+ let h = 0;
85
+ if (max === r1)
86
+ h = (g1 - b1) / d + (g1 < b1 ? 6 : 0);
87
+ else if (max === g1)
88
+ h = (b1 - r1) / d + 2;
89
+ else
90
+ h = (r1 - g1) / d + 4;
91
+ return [(h * 60 + 360) % 360, s, l];
92
+ }
93
+ //# sourceMappingURL=colors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"colors.js","sourceRoot":"","sources":["../../src/utils/colors.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Tracks requests per user and throws if the rate limit is exceeded.
3
+ *
4
+ * @param rateLimits - Store of timestamps per user
5
+ * @param userId - Identifier of the requesting user
6
+ * @param timestamp - Current timestamp in milliseconds
7
+ * @param window - Time window in milliseconds
8
+ * @param limit - Maximum requests allowed in the window
9
+ * @returns false if within limits
10
+ * @throws Error if rate limit is exceeded
11
+ */
12
+ export declare function checkRateLimit(rateLimits: Record<string, number[]>, userId: string, timestamp: number, window?: number, limit?: number): boolean;
13
+ /**
14
+ * Parses a space-separated environment variable into an array.
15
+ *
16
+ * @param key - The environment variable name
17
+ * @returns The parsed array, or null if not set
18
+ */
19
+ export declare function envList(key: string): string[] | null;
20
+ /**
21
+ * Formats a Date to ISO string without timezone suffix.
22
+ *
23
+ * @param date - The date to format
24
+ * @returns ISO-formatted string without trailing Z
25
+ */
26
+ export declare function formatDate(date: Date): string;
27
+ /**
28
+ * Generates a random IPv4 address.
29
+ *
30
+ * @returns A string in the format "X.X.X.X"
31
+ */
32
+ export declare function genIP(): string;
33
+ /**
34
+ * Returns a random element from an array.
35
+ *
36
+ * @param arr - The source array
37
+ * @returns A random element
38
+ */
39
+ export declare function random<T>(arr: T[]): T;
40
+ /**
41
+ * Returns a random integer between min and max (inclusive).
42
+ *
43
+ * @param min - Lower bound
44
+ * @param max - Upper bound
45
+ * @returns A random integer in [min, max]
46
+ */
47
+ export declare function randomNumber(min: number, max: number): number;
48
+ /**
49
+ * Checks if a version string is at least the given minimum.
50
+ *
51
+ * @param version - Version string (e.g. "v4")
52
+ * @param min - Minimum version number
53
+ * @returns true if the version is >= min
54
+ */
55
+ export declare function since(version: string, min: number): boolean;
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Tracks requests per user and throws if the rate limit is exceeded.
3
+ *
4
+ * @param rateLimits - Store of timestamps per user
5
+ * @param userId - Identifier of the requesting user
6
+ * @param timestamp - Current timestamp in milliseconds
7
+ * @param window - Time window in milliseconds
8
+ * @param limit - Maximum requests allowed in the window
9
+ * @returns false if within limits
10
+ * @throws Error if rate limit is exceeded
11
+ */
12
+ export function checkRateLimit(rateLimits, userId, timestamp, window = 10000, limit = 50) {
13
+ for (const key of Object.keys(rateLimits)) {
14
+ if (key !== userId && !rateLimits[key].some((ts) => timestamp - ts < window)) {
15
+ delete rateLimits[key];
16
+ }
17
+ }
18
+ rateLimits[userId] = (rateLimits[userId] ?? []).filter((ts) => timestamp - ts < window);
19
+ if (rateLimits[userId].length >= limit) {
20
+ const remainingTime = Math.ceil((rateLimits[userId][0] + window - timestamp) / 1000);
21
+ throw new Error(`Rate limit exceeded. Try again in ${remainingTime} seconds.`);
22
+ }
23
+ rateLimits[userId].push(timestamp);
24
+ return false;
25
+ }
26
+ /**
27
+ * Parses a space-separated environment variable into an array.
28
+ *
29
+ * @param key - The environment variable name
30
+ * @returns The parsed array, or null if not set
31
+ */
32
+ export function envList(key) {
33
+ const v = process.env[key];
34
+ return v && v !== 'undefined' ? v.split(' ') : null;
35
+ }
36
+ /**
37
+ * Formats a Date to ISO string without timezone suffix.
38
+ *
39
+ * @param date - The date to format
40
+ * @returns ISO-formatted string without trailing Z
41
+ */
42
+ export function formatDate(date) {
43
+ return new Date(date.getTime() - date.getTimezoneOffset() * 60000).toISOString().replace('Z', '');
44
+ }
45
+ /**
46
+ * Generates a random IPv4 address.
47
+ *
48
+ * @returns A string in the format "X.X.X.X"
49
+ */
50
+ export function genIP() {
51
+ return `${randomNumber(0, 255)}.${randomNumber(0, 255)}.${randomNumber(0, 255)}.${randomNumber(0, 255)}`;
52
+ }
53
+ /**
54
+ * Returns a random element from an array.
55
+ *
56
+ * @param arr - The source array
57
+ * @returns A random element
58
+ */
59
+ export function random(arr) {
60
+ return arr[Math.floor(Math.random() * arr.length)];
61
+ }
62
+ /**
63
+ * Returns a random integer between min and max (inclusive).
64
+ *
65
+ * @param min - Lower bound
66
+ * @param max - Upper bound
67
+ * @returns A random integer in [min, max]
68
+ */
69
+ export function randomNumber(min, max) {
70
+ return Math.floor(Math.random() * (max - min + 1)) + min;
71
+ }
72
+ /**
73
+ * Checks if a version string is at least the given minimum.
74
+ *
75
+ * @param version - Version string (e.g. "v4")
76
+ * @param min - Minimum version number
77
+ * @returns true if the version is >= min
78
+ */
79
+ export function since(version, min) {
80
+ return parseInt(version.replace('v', '')) >= min;
81
+ }
82
+ //# sourceMappingURL=helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../src/utils/helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,UAAU,cAAc,CAC1B,UAAoC,EACpC,MAAc,EACd,SAAiB,EACjB,MAAM,GAAG,KAAK,EACd,KAAK,GAAG,EAAE;IAEV,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;QACxC,IAAI,GAAG,KAAK,MAAM,IAAI,CAAC,UAAU,CAAC,GAAG,CAAE,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,SAAS,GAAG,EAAE,GAAG,MAAM,CAAC,EAAE,CAAC;YAC5E,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC;QAC3B,CAAC;IACL,CAAC;IAED,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,SAAS,GAAG,EAAE,GAAG,MAAM,CAAC,CAAC;IAExF,IAAI,UAAU,CAAC,MAAM,CAAE,CAAC,MAAM,IAAI,KAAK,EAAE,CAAC;QACtC,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,MAAM,CAAE,CAAC,CAAC,CAAE,GAAG,MAAM,GAAG,SAAS,CAAC,GAAG,IAAI,CAAC,CAAC;QACvF,MAAM,IAAI,KAAK,CAAC,qCAAqC,aAAa,WAAW,CAAC,CAAC;IACnF,CAAC;IAED,UAAU,CAAC,MAAM,CAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACpC,OAAO,KAAK,CAAC;AACjB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,OAAO,CAAC,GAAW;IAC/B,MAAM,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC3B,OAAO,CAAC,IAAI,CAAC,KAAK,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACxD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CAAC,IAAU;IACjC,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,iBAAiB,EAAE,GAAG,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;AACtG,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,KAAK;IACjB,OAAO,GAAG,YAAY,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,YAAY,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,YAAY,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,YAAY,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;AAC7G,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,MAAM,CAAI,GAAQ;IAC9B,OAAO,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC,CAAE,CAAC;AACxD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,GAAW,EAAE,GAAW;IACjD,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;AAC7D,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,KAAK,CAAC,OAAe,EAAE,GAAW;IAC9C,OAAO,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,IAAI,GAAG,CAAC;AACrD,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { Response } from 'express';
2
+ /**
3
+ * Sends a standardized JSON error response.
4
+ *
5
+ * @param res - Express response object
6
+ * @param status - HTTP status code
7
+ * @param message - Error description
8
+ */
9
+ export declare function error(res: Response, status: number, message: string): void;
@@ -0,0 +1,24 @@
1
+ import { STATUS_MESSAGES } from '../constants.js';
2
+ /**
3
+ * Sends a standardized JSON error response.
4
+ *
5
+ * @param res - Express response object
6
+ * @param status - HTTP status code
7
+ * @param message - Error description
8
+ */
9
+ export function error(res, status, message) {
10
+ const body = {
11
+ message: STATUS_MESSAGES[status] ?? 'Error',
12
+ error: message,
13
+ status,
14
+ };
15
+ if (typeof res.jsonResponse === 'function') {
16
+ res.status(status).jsonResponse(body);
17
+ }
18
+ else {
19
+ res.status(status)
20
+ .setHeader('Content-Type', 'application/json')
21
+ .send(JSON.stringify(body, null, 2));
22
+ }
23
+ }
24
+ //# sourceMappingURL=response.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"response.js","sourceRoot":"","sources":["../../src/utils/response.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAElD;;;;;;GAMG;AACH,MAAM,UAAU,KAAK,CAAC,GAAa,EAAE,MAAc,EAAE,OAAe;IAChE,MAAM,IAAI,GAAG;QACT,OAAO,EAAE,eAAe,CAAC,MAAM,CAAC,IAAI,OAAO;QAC3C,KAAK,EAAE,OAAO;QACd,MAAM;KACT,CAAC;IAEF,IAAI,OAAO,GAAG,CAAC,YAAY,KAAK,UAAU,EAAE,CAAC;QACzC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;IAC1C,CAAC;SAAM,CAAC;QACJ,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC;aACb,SAAS,CAAC,cAAc,EAAE,kBAAkB,CAAC;aAC7C,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC7C,CAAC;AACL,CAAC"}
package/package.json ADDED
@@ -0,0 +1,90 @@
1
+ {
2
+ "version": "6.0.0-pre",
3
+ "name": "@moxon/api",
4
+ "description": "Node.js API with multiple features. Check the documentation at https://docs.sylvain.sh",
5
+ "main": "./dist/modules/v6.js",
6
+ "types": "./dist/modules/v6.d.ts",
7
+ "type": "module",
8
+ "scripts": {
9
+ "prepare": "npm run clean && tsc",
10
+ "clean": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"",
11
+ "dev": "tsx watch src/app.ts",
12
+ "build": "npm run clean && tsc",
13
+ "start": "node dist/app.js",
14
+ "check": "tsc --noEmit -p tsconfig.test.json && eslint src/ tests/ && prettier --check .",
15
+ "format": "prettier --write . && eslint --fix src/ tests/",
16
+ "test": "NODE_ENV=test DOCS_URL=https://docs.example.test node --import tsx --test tests/unit/*.test.ts tests/integration/*.test.ts"
17
+ },
18
+ "engines": {
19
+ "node": ">=22.12.0"
20
+ },
21
+ "exports": {
22
+ ".": {
23
+ "types": "./dist/modules/v6.d.ts",
24
+ "default": "./dist/modules/v6.js"
25
+ },
26
+ "./server": {
27
+ "types": "./dist/app.d.ts",
28
+ "default": "./dist/app.js"
29
+ },
30
+ "./v4": {
31
+ "types": "./dist/modules/v4.d.ts",
32
+ "default": "./dist/modules/v4.js"
33
+ },
34
+ "./v5": {
35
+ "types": "./dist/modules/v5.d.ts",
36
+ "default": "./dist/modules/v5.js"
37
+ },
38
+ "./v6": {
39
+ "types": "./dist/modules/v6.d.ts",
40
+ "default": "./dist/modules/v6.js"
41
+ },
42
+ "./package.json": "./package.json"
43
+ },
44
+ "dependencies": {
45
+ "@20syldev/logger.ts": "^1.0.2",
46
+ "@types/express": "^5.0.0",
47
+ "@types/node": "^22.19.17",
48
+ "canvas": "^3.1.0",
49
+ "cors": "^2.8.5",
50
+ "dotenv": "^16.4.7",
51
+ "express": "^5.1.0",
52
+ "ical.js": "^2.1.0",
53
+ "qrcode": "^1.5.4",
54
+ "random": "^5.3.0",
55
+ "uuid": "^14.0.0"
56
+ },
57
+ "devDependencies": {
58
+ "@eslint/js": "^9.24.0",
59
+ "@types/cors": "^2.8.17",
60
+ "@types/qrcode": "^1.5.6",
61
+ "@types/uuid": "^10.0.0",
62
+ "eslint": "^9.24.0",
63
+ "eslint-config-prettier": "^10.1.1",
64
+ "eslint-plugin-simple-import-sort": "^13.0.0",
65
+ "prettier": "^3.5.3",
66
+ "tsx": "^4.19.0",
67
+ "typescript": "^5.7.0",
68
+ "typescript-eslint": "^8.29.0"
69
+ },
70
+ "publishConfig": {
71
+ "access": "public"
72
+ },
73
+ "repository": {
74
+ "type": "git",
75
+ "url": "git+https://github.com/20syldev/moxon.git"
76
+ },
77
+ "keywords": [
78
+ "api",
79
+ "express",
80
+ "utility",
81
+ "math",
82
+ "typescript"
83
+ ],
84
+ "author": "Sylvain L.",
85
+ "license": "BSD 3-Clause",
86
+ "bugs": {
87
+ "url": "https://github.com/20syldev/moxon/issues"
88
+ },
89
+ "homepage": "https://api.sylvain.sh"
90
+ }