@arkyn/shared 3.0.1-beta.9 โ†’ 3.0.1-beta.91

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 (66) hide show
  1. package/README.md +452 -67
  2. package/dist/bundle.js +2337 -0
  3. package/dist/bundle.umd.cjs +6 -0
  4. package/dist/formats/formatToCapitalizeFirstWordLetter.d.ts +35 -0
  5. package/dist/formats/formatToCapitalizeFirstWordLetter.d.ts.map +1 -0
  6. package/dist/formats/formatToCapitalizeFirstWordLetter.js +42 -0
  7. package/dist/index.d.ts +2 -7
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +2 -8
  10. package/dist/services/isHtml.d.ts +22 -0
  11. package/dist/services/isHtml.d.ts.map +1 -0
  12. package/dist/services/isHtml.js +24 -0
  13. package/package.json +26 -6
  14. package/dist/validations/validateCep.d.ts +0 -24
  15. package/dist/validations/validateCep.d.ts.map +0 -1
  16. package/dist/validations/validateCep.js +0 -33
  17. package/dist/validations/validateCnpj.d.ts +0 -22
  18. package/dist/validations/validateCnpj.d.ts.map +0 -1
  19. package/dist/validations/validateCnpj.js +0 -52
  20. package/dist/validations/validateCpf.d.ts +0 -24
  21. package/dist/validations/validateCpf.d.ts.map +0 -1
  22. package/dist/validations/validateCpf.js +0 -54
  23. package/dist/validations/validateDate.d.ts +0 -34
  24. package/dist/validations/validateDate.d.ts.map +0 -1
  25. package/dist/validations/validateDate.js +0 -73
  26. package/dist/validations/validatePassword.d.ts +0 -21
  27. package/dist/validations/validatePassword.d.ts.map +0 -1
  28. package/dist/validations/validatePassword.js +0 -34
  29. package/dist/validations/validatePhone.d.ts +0 -29
  30. package/dist/validations/validatePhone.d.ts.map +0 -1
  31. package/dist/validations/validatePhone.js +0 -44
  32. package/dist/validations/validateRg.d.ts +0 -22
  33. package/dist/validations/validateRg.d.ts.map +0 -1
  34. package/dist/validations/validateRg.js +0 -31
  35. package/src/formats/formatDate.ts +0 -92
  36. package/src/formats/formatJsonObject.ts +0 -90
  37. package/src/formats/formatJsonString.ts +0 -50
  38. package/src/formats/formatToCep.ts +0 -39
  39. package/src/formats/formatToCnpj.ts +0 -40
  40. package/src/formats/formatToCpf.ts +0 -40
  41. package/src/formats/formatToCpfCnpj.ts +0 -38
  42. package/src/formats/formatToCurrency.ts +0 -63
  43. package/src/formats/formatToDate.ts +0 -70
  44. package/src/formats/formatToEllipsis.ts +0 -25
  45. package/src/formats/formatToHiddenDigits.ts +0 -92
  46. package/src/formats/formatToPhone.ts +0 -170
  47. package/src/generators/generateColorByString.ts +0 -33
  48. package/src/generators/generateId.ts +0 -61
  49. package/src/generators/generateSlug.ts +0 -31
  50. package/src/index.ts +0 -36
  51. package/src/services/calculateCardInstallment.ts +0 -73
  52. package/src/services/ensureQuotes.ts +0 -25
  53. package/src/services/maskSensitiveData.ts +0 -68
  54. package/src/services/removeCurrencySymbols.ts +0 -29
  55. package/src/services/removeNonNumeric.ts +0 -20
  56. package/src/services/stripHtmlTags.ts +0 -20
  57. package/src/services/truncateLargeFields.ts +0 -69
  58. package/src/validations/validateCep.ts +0 -41
  59. package/src/validations/validateCnpj.ts +0 -65
  60. package/src/validations/validateCpf.ts +0 -62
  61. package/src/validations/validateDate.ts +0 -86
  62. package/src/validations/validatePassword.ts +0 -41
  63. package/src/validations/validatePhone.ts +0 -50
  64. package/src/validations/validateRg.ts +0 -37
  65. package/tsconfig.json +0 -20
  66. package/vitest.config.ts +0 -5
package/README.md CHANGED
@@ -1,119 +1,504 @@
1
- The `@arkyn/shared` package provides reusable utilities such as formatting functions, generators, services, and validations. It is designed to be used across different parts of a project, offering common and practical solutions to streamline development.
1
+ # @arkyn/shared
2
2
 
3
- ---
3
+ A comprehensive collection of reusable utilities for consistent data handling across your applications. Provides formatting functions, validation tools, generators, and services to streamline common development tasks.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@arkyn/shared.svg)](https://www.npmjs.com/package/@arkyn/shared)
6
+ [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
7
+ [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)
8
+
9
+ ## โœจ Features
4
10
 
5
- ## Installation
11
+ - ๐Ÿ“… **Date Utilities** - Flexible date manipulation and timezone support
12
+ - ๐Ÿฆ **Financial Tools** - Currency formatting and installment calculations
13
+ - ๐Ÿ”’ **Brazilian Validators** - CPF, CNPJ, CEP, RG, and phone number validation
14
+ - ๐ŸŽจ **String Utilities** - Formatting, masking, and text manipulation
15
+ - ๐Ÿ”ง **Generators** - ID generation, slugs, colors, and more
16
+ - ๐Ÿ›ก๏ธ **Data Security** - Sensitive data masking and sanitization
17
+ - ๐ŸŒ **Internationalization** - Multi-locale support for formatting
6
18
 
7
- Install the package using npm:
19
+ ## ๐Ÿ“ฆ Installation
8
20
 
9
21
  ```bash
10
22
  npm install @arkyn/shared
11
23
  ```
12
24
 
13
- ---
25
+ ## ๐Ÿš€ Quick Start
26
+
27
+ ```typescript
28
+ import {
29
+ formatToCpf,
30
+ validateCpf,
31
+ formatToCurrency,
32
+ generateId,
33
+ } from "@arkyn/shared";
14
34
 
15
- ## Features
35
+ // Format and validate CPF
36
+ const cpf = formatToCpf("12345678901"); // "123.456.789-01"
37
+ const isValid = validateCpf(cpf); // true
16
38
 
17
- ### Formatting
39
+ // Format currency
40
+ const price = formatToCurrency(1299.99); // "R$ 1.299,99"
18
41
 
19
- - **`formatDate(date: dateString[], inputFormat: "brazilianDate" | "isoDate" | "timestamp", outputFormat: string, timezone?: number): string`**
20
- Formats a date into a readable string.
42
+ // Generate unique ID
43
+ const id = generateId(); // "uuid-v4-string"
44
+ ```
21
45
 
22
- - **`formatJsonObject(obj: object): string`**
23
- Converts a JSON object into a formatted string.
46
+ ## ๐Ÿ“‹ API Reference
24
47
 
25
- - **`formatJsonString(json: string): object`**
26
- Converts a JSON string into an object.
48
+ ### ๐Ÿ“… Date Formatting
27
49
 
28
- - **`formatToCep(value: string): string`**
29
- Formats a string into the CEP format (`XXXXX-XXX`).
50
+ #### formatDate(date, inputFormat, outputFormat, timezone?)
30
51
 
31
- - **`formatToCnpj(value: string): string`**
32
- Formats a string into the CNPJ format (`XX.XXX.XXX/XXXX-XX`).
52
+ Formats dates with timezone support.
33
53
 
34
- - **`formatToCpf(value: string): string`**
35
- Formats a string into the CPF format (`XXX.XXX.XXX-XX`).
54
+ ```typescript
55
+ import { formatDate } from "@arkyn/shared";
36
56
 
37
- - **`formatToCpfCnpj(value: string): string`**
38
- Formats a string into either CPF or CNPJ format, depending on its length.
57
+ // Format ISO date to Brazilian format
58
+ const formatted = formatDate("2023-12-25", "isoDate", "DD/MM/YYYY");
59
+ // Result: "25/12/2023"
39
60
 
40
- - **`formatToCurrency(value: number): string`**
41
- Converts a number into a currency format.
61
+ // With timezone
62
+ const withTz = formatDate(
63
+ "2023-12-25T10:00:00Z",
64
+ "isoDate",
65
+ "DD/MM/YYYY HH:mm",
66
+ -3
67
+ );
68
+ // Result: "25/12/2023 07:00"
69
+ ```
42
70
 
43
- - **`formatToDate(date: dateString[], inputFormat: "brazilianDate" | "isoDate" | "timestamp", timezone?: number): Date`**
44
- Formats a date into a Date class.
71
+ #### formatToDate(date, inputFormat, timezone?)
45
72
 
46
- - **`formatToEllipsis(value: string, maxLength: number): string`**
47
- Truncates a string and appends an ellipsis if it exceeds the maximum length.
73
+ Converts strings to Date objects.
48
74
 
49
- - **`formatToHiddenDigits(value: string): string`**
50
- Masks part of a string by replacing it with asterisks.
75
+ ```typescript
76
+ import { formatToDate } from "@arkyn/shared";
51
77
 
52
- - **`formatToPhone(value: string): string`**
53
- Formats a string into a phone number format.
78
+ const date = formatToDate("25/12/2023", "brazilianDate");
79
+ // Result: Date object
80
+ ```
54
81
 
55
- ---
82
+ ### ๐Ÿฆ Financial Formatting
83
+
84
+ #### formatToCurrency(value: number): string
85
+
86
+ Formats numbers to Brazilian currency format.
87
+
88
+ ```typescript
89
+ import { formatToCurrency } from "@arkyn/shared";
90
+
91
+ formatToCurrency(1299.99); // "R$ 1.299,99"
92
+ formatToCurrency(0.5); // "R$ 0,50"
93
+ ```
94
+
95
+ #### calculateCardInstallment(total: number, installments: number): number[]
96
+
97
+ Calculates installment values for credit card payments.
98
+
99
+ ```typescript
100
+ import { calculateCardInstallment } from "@arkyn/shared";
101
+
102
+ const installments = calculateCardInstallment(1000, 10);
103
+ // Result: [100, 100, 100, 100, 100, 100, 100, 100, 100, 100]
104
+ ```
105
+
106
+ ### ๐Ÿ‡ง๐Ÿ‡ท Brazilian Document Formatting
56
107
 
57
- ### Generators
108
+ #### formatToCpf(value: string): string
109
+
110
+ Formats strings to CPF format.
111
+
112
+ ```typescript
113
+ import { formatToCpf } from "@arkyn/shared";
114
+
115
+ formatToCpf("12345678901"); // "123.456.789-01"
116
+ ```
117
+
118
+ #### formatToCnpj(value: string): string
119
+
120
+ Formats strings to CNPJ format.
121
+
122
+ ```typescript
123
+ import { formatToCnpj } from "@arkyn/shared";
124
+
125
+ formatToCnpj("12345678000195"); // "12.345.678/0001-95"
126
+ ```
127
+
128
+ #### formatToCpfCnpj(value: string): string
129
+
130
+ Auto-detects and formats CPF or CNPJ.
131
+
132
+ ```typescript
133
+ import { formatToCpfCnpj } from "@arkyn/shared";
134
+
135
+ formatToCpfCnpj("12345678901"); // "123.456.789-01" (CPF)
136
+ formatToCpfCnpj("12345678000195"); // "12.345.678/0001-95" (CNPJ)
137
+ ```
138
+
139
+ #### formatToCep(value: string): string
140
+
141
+ Formats strings to CEP format.
142
+
143
+ ```typescript
144
+ import { formatToCep } from "@arkyn/shared";
145
+
146
+ formatToCep("01234567"); // "01234-567"
147
+ ```
58
148
 
59
- - **`generateColorByString(value: string): string`**
60
- Generates a hexadecimal color based on a string.
149
+ #### formatToPhone(value: string): string
61
150
 
62
- - **`generateId(): string`**
63
- Generates a unique identifier.
151
+ Formats phone numbers.
64
152
 
65
- - **`generateSlug(value: string): string`**
66
- Converts a string into a URL-friendly slug.
153
+ ```typescript
154
+ import { formatToPhone } from "@arkyn/shared";
155
+
156
+ formatToPhone("11987654321"); // "(11) 98765-4321"
157
+ ```
67
158
 
68
159
  ---
69
160
 
70
- ### Services
161
+ ### ๐ŸŽจ String Utilities
162
+
163
+ #### formatToEllipsis(value: string, maxLength: number): string
164
+
165
+ Truncates strings with ellipsis.
166
+
167
+ ```typescript
168
+ import { formatToEllipsis } from "@arkyn/shared";
169
+
170
+ formatToEllipsis("This is a very long text", 10); // "This is a..."
171
+ ```
172
+
173
+ #### formatToHiddenDigits(value: string): string
174
+
175
+ Masks sensitive information.
176
+
177
+ ```typescript
178
+ import { formatToHiddenDigits } from "@arkyn/shared";
179
+
180
+ formatToHiddenDigits("123456789"); // "12***6789"
181
+ ```
182
+
183
+ #### formatToCapitalizeFirstWordLetter(value: string): string
184
+
185
+ Capitalizes the first letter of each word.
186
+
187
+ ```typescript
188
+ import { formatToCapitalizeFirstWordLetter } from "@arkyn/shared";
189
+
190
+ formatToCapitalizeFirstWordLetter("hello world"); // "Hello World"
191
+ ```
192
+
193
+ #### stripHtmlTags(value: string): string
194
+
195
+ Removes HTML tags from strings.
71
196
 
72
- - **`calculateCardInstallment(total: number, installments: number): number[]`**
73
- Calculates the installment values for a given total.
197
+ ```typescript
198
+ import { stripHtmlTags } from "@arkyn/shared";
74
199
 
75
- - **`ensureQuotes(rawValue: string): string`**
76
- Ensures that a given rawValue string is enclosed in quotes.
200
+ stripHtmlTags("<p>Hello <strong>World</strong></p>"); // "Hello World"
201
+ ```
202
+
203
+ ### ๐Ÿ“„ JSON Utilities
204
+
205
+ #### formatJsonObject(obj: object): string
206
+
207
+ Converts objects to formatted JSON strings.
208
+
209
+ ```typescript
210
+ import { formatJsonObject } from "@arkyn/shared";
77
211
 
78
- - **`maskSensitiveData(data: string): string`**
79
- Masks sensitive data in a string.
212
+ const obj = { name: "John", age: 30 };
213
+ formatJsonObject(obj); // Pretty-printed JSON string
214
+ ```
215
+
216
+ #### formatJsonString(json: string): object
80
217
 
81
- - **`removeNonNumeric(value: string): string`**
82
- Removes all non-numeric characters from a string.
218
+ Parses JSON strings safely.
83
219
 
84
- - **`truncateLargeFields(obj: object, maxLength: number): object`**
85
- Truncates large fields in an object to a specified maximum length.
220
+ ```typescript
221
+ import { formatJsonString } from "@arkyn/shared";
222
+
223
+ const parsed = formatJsonString('{"name":"John"}');
224
+ // Result: { name: "John" }
225
+ ```
86
226
 
87
227
  ---
88
228
 
89
- ### Validations
229
+ ### ๐Ÿ”ง Generators
230
+
231
+ #### generateId(): string
232
+
233
+ Generates unique identifiers using UUID v4.
234
+
235
+ ```typescript
236
+ import { generateId } from "@arkyn/shared";
237
+
238
+ const id = generateId(); // "f47ac10b-58cc-4372-a567-0e02b2c3d479"
239
+ ```
240
+
241
+ #### generateSlug(value: string): string
242
+
243
+ Creates URL-friendly slugs.
244
+
245
+ ```typescript
246
+ import { generateSlug } from "@arkyn/shared";
247
+
248
+ generateSlug("Hello World! How are you?"); // "hello-world-how-are-you"
249
+ ```
250
+
251
+ #### generateColorByString(value: string): string
252
+
253
+ Generates consistent colors from strings.
254
+
255
+ ```typescript
256
+ import { generateColorByString } from "@arkyn/shared";
257
+
258
+ generateColorByString("John Doe"); // "#3498db" (always same color for same input)
259
+ ```
260
+
261
+ ### ๐Ÿ›ก๏ธ Data Security & Sanitization
262
+
263
+ #### maskSensitiveData(data: string): string
264
+
265
+ Masks sensitive information in logs and outputs.
266
+
267
+ ```typescript
268
+ import { maskSensitiveData } from "@arkyn/shared";
269
+
270
+ maskSensitiveData("user@email.com"); // "us***@email.com"
271
+ ```
272
+
273
+ #### removeNonNumeric(value: string): string
274
+
275
+ Removes all non-numeric characters.
276
+
277
+ ```typescript
278
+ import { removeNonNumeric } from "@arkyn/shared";
279
+
280
+ removeNonNumeric("(11) 98765-4321"); // "11987654321"
281
+ ```
282
+
283
+ #### removeCurrencySymbols(value: string): string
90
284
 
91
- - **`validateCep(value: string): boolean`**
92
- Validates whether a string is a valid CEP.
285
+ Removes currency symbols and formatting.
93
286
 
94
- - **`validateCnpj(value: string): boolean`**
95
- Validates whether a string is a valid CNPJ.
287
+ ```typescript
288
+ import { removeCurrencySymbols } from "@arkyn/shared";
96
289
 
97
- - **`validateCpf(value: string): boolean`**
98
- Validates whether a string is a valid CPF.
290
+ removeCurrencySymbols("R$ 1.299,99"); // "1299.99"
291
+ ```
99
292
 
100
- - **`validateDate(value: string): boolean`**
101
- Validates whether a string is a valid date.
293
+ #### ensureQuotes(rawValue: string): string
102
294
 
103
- - **`validatePhone(value: string): boolean`**
104
- Validates whether a string is a valid phone number.
295
+ Ensures strings are properly quoted.
105
296
 
106
- - **`validateRg(value: string): boolean`**
107
- Validates whether a string is a valid ID (RG).
297
+ ```typescript
298
+ import { ensureQuotes } from "@arkyn/shared";
299
+
300
+ ensureQuotes("hello"); // '"hello"'
301
+ ensureQuotes('"hello"'); // '"hello"' (no double quotes)
302
+ ```
303
+
304
+ #### truncateLargeFields(obj: object, maxLength: number): object
305
+
306
+ Truncates large text fields in objects.
307
+
308
+ ```typescript
309
+ import { truncateLargeFields } from "@arkyn/shared";
310
+
311
+ const data = { description: "Very long text..." };
312
+ truncateLargeFields(data, 10); // { description: 'Very long...' }
313
+ ```
108
314
 
109
315
  ---
110
316
 
111
- ## Contribution
317
+ ### โœ… Validation Functions
318
+
319
+ #### validateCpf(value: string): boolean
320
+
321
+ Validates Brazilian CPF numbers.
322
+
323
+ ```typescript
324
+ import { validateCpf } from "@arkyn/shared";
325
+
326
+ validateCpf("123.456.789-01"); // true/false
327
+ validateCpf("12345678901"); // true/false (accepts without formatting)
328
+ ```
112
329
 
113
- Contributions are welcome! Feel free to open issues or submit pull requests to improve the project.
330
+ #### validateCnpj(value: string): boolean
331
+
332
+ Validates Brazilian CNPJ numbers.
333
+
334
+ ```typescript
335
+ import { validateCnpj } from "@arkyn/shared";
336
+
337
+ validateCnpj("12.345.678/0001-95"); // true/false
338
+ ```
339
+
340
+ #### validateCep(value: string): boolean
341
+
342
+ Validates Brazilian postal codes.
343
+
344
+ ```typescript
345
+ import { validateCep } from "@arkyn/shared";
346
+
347
+ validateCep("01234-567"); // true/false
348
+ validateCep("01234567"); // true/false (accepts without formatting)
349
+ ```
350
+
351
+ #### validatePhone(value: string): boolean
352
+
353
+ Validates Brazilian phone numbers.
354
+
355
+ ```typescript
356
+ import { validatePhone } from "@arkyn/shared";
357
+
358
+ validatePhone("(11) 98765-4321"); // true/false
359
+ validatePhone("11987654321"); // true/false
360
+ ```
361
+
362
+ #### validateRg(value: string): boolean
363
+
364
+ Validates Brazilian RG (ID) numbers.
365
+
366
+ ```typescript
367
+ import { validateRg } from "@arkyn/shared";
368
+
369
+ validateRg("12.345.678-9"); // true/false
370
+ ```
371
+
372
+ #### validateDate(value: string): boolean
373
+
374
+ Validates date strings.
375
+
376
+ ```typescript
377
+ import { validateDate } from "@arkyn/shared";
378
+
379
+ validateDate("25/12/2023"); // true/false
380
+ validateDate("2023-12-25"); // true/false
381
+ ```
382
+
383
+ #### validatePassword(value: string): boolean
384
+
385
+ Validates password strength.
386
+
387
+ ```typescript
388
+ import { validatePassword } from "@arkyn/shared";
389
+
390
+ validatePassword("MyPassword123!"); // true/false
391
+ ```
392
+
393
+ ## ๐Ÿ”ง Advanced Usage
394
+
395
+ ### Complete Form Validation
396
+
397
+ ```typescript
398
+ import {
399
+ validateCpf,
400
+ validatePhone,
401
+ validateCep,
402
+ formatToCpf,
403
+ formatToPhone,
404
+ formatToCep,
405
+ } from "@arkyn/shared";
406
+
407
+ function validateUserForm(data) {
408
+ const errors = {};
409
+
410
+ // Validate and format CPF
411
+ if (!validateCpf(data.cpf)) {
412
+ errors.cpf = "Invalid CPF";
413
+ } else {
414
+ data.cpf = formatToCpf(data.cpf);
415
+ }
416
+
417
+ // Validate and format phone
418
+ if (!validatePhone(data.phone)) {
419
+ errors.phone = "Invalid phone number";
420
+ } else {
421
+ data.phone = formatToPhone(data.phone);
422
+ }
423
+
424
+ // Validate and format CEP
425
+ if (!validateCep(data.cep)) {
426
+ errors.cep = "Invalid postal code";
427
+ } else {
428
+ data.cep = formatToCep(data.cep);
429
+ }
430
+
431
+ return { isValid: Object.keys(errors).length === 0, errors, data };
432
+ }
433
+ ```
434
+
435
+ ### Data Processing Pipeline
436
+
437
+ ```typescript
438
+ import {
439
+ removeNonNumeric,
440
+ formatToCurrency,
441
+ calculateCardInstallment,
442
+ generateId,
443
+ } from "@arkyn/shared";
444
+
445
+ function processOrder(orderData) {
446
+ // Clean price input
447
+ const numericPrice = removeNonNumeric(orderData.price);
448
+ const price = parseFloat(numericPrice) / 100; // Convert cents to reais
449
+
450
+ // Format for display
451
+ const formattedPrice = formatToCurrency(price);
452
+
453
+ // Calculate installments
454
+ const installments = calculateCardInstallment(price, 12);
455
+
456
+ // Generate order ID
457
+ const orderId = generateId();
458
+
459
+ return {
460
+ id: orderId,
461
+ price: formattedPrice,
462
+ installmentOptions: installments.map((value, index) => ({
463
+ number: index + 1,
464
+ value: formatToCurrency(value),
465
+ })),
466
+ };
467
+ }
468
+ ```
469
+
470
+ ## ๐Ÿงช Development
471
+
472
+ ```bash
473
+ # Install dependencies
474
+ bun install
475
+
476
+ # Build the package
477
+ bun run build
478
+
479
+ # Run tests
480
+ bun run test
481
+
482
+ # Type check
483
+ bun run typecheck
484
+ ```
114
485
 
115
486
  ---
116
487
 
117
- ## License
488
+ ## ๐Ÿค Contributing
489
+
490
+ Contributions are welcome! Please read our contributing guidelines and submit pull requests to help improve the package.
491
+
492
+ ## ๐Ÿ“„ License
493
+
494
+ This project is licensed under the Apache 2.0 License - see the [LICENSE](./LICENSE.txt) file for details.
495
+
496
+ ## ๐Ÿ”— Links
497
+
498
+ - [GitHub Repository](https://github.com/Lucas-Eduardo-Goncalves/arkyn)
499
+ - [NPM Package](https://www.npmjs.com/package/@arkyn/shared)
500
+ - [Full Documentation](https://github.com/Lucas-Eduardo-Goncalves/arkyn#readme)
501
+
502
+ ---
118
503
 
119
- This project is licensed under the Apache 2.0 License. See the `LICENSE` file for more details.
504
+ Made with โค๏ธ by the Arkyn team