@antmind/otp 0.1.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.
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@antmind/otp",
3
+ "version": "0.1.0",
4
+ "description": "OTP (One-Time Password) library for Node.js and browsers.",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "scripts": {
8
+ "build": "tsc",
9
+ "test": "jest --coverage"
10
+ },
11
+ "keywords": [
12
+ "otp",
13
+ "hotp",
14
+ "totp"
15
+ ],
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git+https://github.com/ghosind/node-otp.git"
19
+ },
20
+ "homepage": "https://github.com/ghosind/node-otp#readme",
21
+ "bugs": {
22
+ "url": "https://github.com/ghosind/node-otp/issues"
23
+ },
24
+ "author": "Chen Su",
25
+ "license": "MIT",
26
+ "directories": {
27
+ "test": "tests"
28
+ },
29
+ "dependencies": {
30
+ "@antmind/encoding": "^0.1.0"
31
+ },
32
+ "devDependencies": {
33
+ "@types/jest": "^30.0.0",
34
+ "@types/node": "^25.0.3",
35
+ "jest": "^30.2.0",
36
+ "ts-jest": "^29.4.6",
37
+ "typescript": "^5.9.3"
38
+ }
39
+ }
package/src/crypto.ts ADDED
@@ -0,0 +1,25 @@
1
+ import { createHmac } from 'crypto';
2
+
3
+ /**
4
+ * The supported HMAC algorithms.
5
+ */
6
+ export type Algorithm = 'SHA1' | 'SHA256' | 'SHA512';
7
+
8
+ /**
9
+ * Generates an HMAC digest for the given message using the specified algorithm and key.
10
+ *
11
+ * @param algorithm The HMAC algorithm to use. Default is 'SHA1'.
12
+ * @param key The secret key used for HMAC generation.
13
+ * @param message The message to be hashed.
14
+ * @returns The generated HMAC digest as a Uint8Array.
15
+ */
16
+ export const hmac = async (
17
+ algorithm: Algorithm = 'SHA1',
18
+ key: Uint8Array,
19
+ message: Uint8Array,
20
+ ) => {
21
+ const hmac = createHmac(algorithm, key);
22
+ hmac.update(message);
23
+
24
+ return new Uint8Array(hmac.digest());
25
+ }
package/src/hotp.ts ADDED
@@ -0,0 +1,47 @@
1
+ import { OTP } from './otp';
2
+
3
+ /**
4
+ * HMAC-based One-Time Password (HOTP) generator and verifier.
5
+ */
6
+ export class HOTP extends OTP {
7
+ /**
8
+ * Generates an HOTP code based on the provided secret and counter.
9
+ *
10
+ * @param secret The shared secret key used for generating the HOTP code.
11
+ * @param counter The counter value used for generating the HOTP code.
12
+ * @returns The generated HOTP code as a string.
13
+ */
14
+ async generate(secret: string, counter?: number): Promise<string> {
15
+ return this.generateCode(secret, counter || 0);
16
+ }
17
+
18
+ /**
19
+ * Verifies the provided HOTP code against the generated code for the given secret and counter.
20
+ *
21
+ * @param secret The shared secret key used for generating the HOTP code.
22
+ * @param token The HOTP code to verify.
23
+ * @param counter The counter value used for generating the HOTP code.
24
+ * @returns A boolean indicating whether the HOTP code is valid.
25
+ */
26
+ async verify(secret: string, token: string, counter?: number): Promise<boolean> {
27
+ return this.verifyCode(secret, token, counter || 0);
28
+ }
29
+
30
+ /**
31
+ * Generates the OTP URI for the given parameters.
32
+ *
33
+ * @param secret The shared secret key used for generating the HOTP code.
34
+ * @param accountName The account name associated with the OTP.
35
+ * @param counter The counter value used for generating the HOTP code.
36
+ * @returns The generated OTP URI as a string.
37
+ */
38
+ getURI(secret: string, accountName: string, counter?: number): string {
39
+ const params: Record<string, string> = {};
40
+
41
+ if (counter !== undefined) {
42
+ params['counter'] = counter.toString();
43
+ }
44
+
45
+ return this.buildURI('hotp', secret, accountName, params);
46
+ }
47
+ }
package/src/index.ts ADDED
@@ -0,0 +1,3 @@
1
+ export { Algorithm } from './crypto';
2
+ export { TOTP, TOTPOptions } from './totp';
3
+ export { HOTP } from './hotp';
package/src/otp.ts ADDED
@@ -0,0 +1,145 @@
1
+ import { Base32Encoding } from '@antmind/encoding';
2
+ import { Algorithm, hmac } from './crypto';
3
+
4
+ const DefaultAlgorithm: Algorithm = 'SHA1';
5
+ const DefaultDigits = 6;
6
+
7
+ export interface OTPOptions {
8
+ /**
9
+ * The algorithm used for the OTP generation, typically 'SHA1', 'SHA256', or 'SHA512'.
10
+ * Default is 'SHA1'.
11
+ */
12
+ algorithm?: Algorithm;
13
+
14
+ /**
15
+ * The number of digits in the generated OTP, typically 6 or 8. Default is 6.
16
+ */
17
+ digits?: number;
18
+
19
+ /**
20
+ * The issuer name to be included in the OTP URI.
21
+ */
22
+ issuer?: string;
23
+ }
24
+
25
+ export abstract class OTP {
26
+ /**
27
+ * The algorithm used for the OTP generation, typically 'SHA1', 'SHA256', or 'SHA512'.
28
+ * Default is 'SHA1'.
29
+ */
30
+ algorithm?: Algorithm;
31
+
32
+ /**
33
+ * The number of digits in the generated OTP, typically 6 or 8. Default is 6.
34
+ */
35
+ digits?: number;
36
+
37
+ /**
38
+ * The issuer name to be included in the OTP URI.
39
+ */
40
+ issuer?: string | undefined;
41
+
42
+ private base32?: Base32Encoding;
43
+
44
+ constructor(options?: OTPOptions) {
45
+ this.algorithm = options?.algorithm || DefaultAlgorithm;
46
+ this.digits = options?.digits || DefaultDigits;
47
+ this.issuer = options?.issuer;
48
+ }
49
+
50
+ abstract generate(secret: string, counterOrTime?: number): Promise<string>;
51
+
52
+ abstract verify(secret: string, token: string, counterOrTime?: number): Promise<boolean>;
53
+
54
+ /**
55
+ * Verifies the provided OTP code against the generated code for the given secret and counter or
56
+ * time.
57
+ *
58
+ * @param secret The shared secret key used for generating the OTP code.
59
+ * @param token The OTP code to verify.
60
+ * @param counter The counter or time value used for generating the OTP code.
61
+ * @returns A boolean indicating whether the OTP code is valid.
62
+ */
63
+ protected async verifyCode(secret: string, token: string, counter: number): Promise<boolean> {
64
+ const generatedCode = await this.generateCode(secret, counter);
65
+
66
+ return generatedCode === token;
67
+ }
68
+
69
+ /**
70
+ * Generates an OTP code based on the provided secret and counter or time.
71
+ *
72
+ * @param secret The shared secret key used for generating the OTP code.
73
+ * @param counter The counter or time value used for generating the OTP code.
74
+ * @returns The generated OTP code as a string.
75
+ */
76
+ protected async generateCode(secret: string, counter: number): Promise<string> {
77
+ const message = new Uint8Array(8);
78
+ const view = new DataView(message.buffer);
79
+ view.setUint32(4, counter, false);
80
+ const secretBytes = new TextEncoder().encode(secret);
81
+
82
+ const hash = await hmac(this.algorithm, secretBytes, message);
83
+ const offset = (hash[hash.length - 1] || 0) & 0x0f;
84
+ const code = (((hash[offset] || 0) & 0x7F) << 24)
85
+ | (((hash[offset+1] || 0) & 0xFF) << 16)
86
+ | (((hash[offset+2] || 0) & 0xFF) << 8)
87
+ | ((hash[offset+3] || 0) & 0xFF);
88
+ const mod = 10 ** (this.digits || DefaultDigits);
89
+ const otp = (code % mod).toString().padStart(this.digits || DefaultDigits, '0');
90
+
91
+ return otp;
92
+ }
93
+
94
+ /**
95
+ * Builds the OTP URI for the given OTP type, secret, account name, and other parameters.
96
+ *
97
+ * @param type The type of OTP, either 'totp' or 'hotp'.
98
+ * @param secret The shared secret key used for generating the OTP code.
99
+ * @param accountName The account name associated with the OTP.
100
+ * @param otherParams Additional parameters to include in the OTP URI.
101
+ * @returns The generated OTP URI as a string.
102
+ */
103
+ protected buildURI(type: 'totp' | 'hotp', secret: string, accountName: string, otherParams: {
104
+ [key: string]: string | number;
105
+ }): string {
106
+ const params = new URLSearchParams();
107
+
108
+ const base32 = this.getBase32();
109
+ const secretBase32 = base32.encode(secret);
110
+ params.append('secret', secretBase32);
111
+
112
+ if (this.issuer) {
113
+ params.append('issuer', this.issuer);
114
+ }
115
+ if (this.algorithm && this.algorithm !== DefaultAlgorithm) {
116
+ params.append('algorithm', this.algorithm);
117
+ }
118
+ if (this.digits && this.digits !== DefaultDigits) {
119
+ params.append('digits', (this.digits).toString());
120
+ }
121
+
122
+ for (const [key, value] of Object.entries(otherParams)) {
123
+ params.append(key, value.toString());
124
+ }
125
+
126
+ const path = this.issuer
127
+ ? `${encodeURIComponent(this.issuer)}:${encodeURIComponent(accountName)}`
128
+ : encodeURIComponent(accountName);
129
+
130
+ return `otpauth://${type}/${path}?${params.toString()}`;
131
+ }
132
+
133
+ /**
134
+ * Gets the Base32 encoding instance.
135
+ *
136
+ * @returns The base32 encoding instance.
137
+ */
138
+ private getBase32(): Base32Encoding {
139
+ if (!this.base32) {
140
+ this.base32 = new Base32Encoding({ padChar: '' });
141
+ }
142
+
143
+ return this.base32;
144
+ }
145
+ }
package/src/totp.ts ADDED
@@ -0,0 +1,77 @@
1
+ import { OTP, OTPOptions } from './otp';
2
+
3
+ const DefaultPeriod = 30;
4
+
5
+ export interface TOTPOptions extends OTPOptions {
6
+ /**
7
+ * The time period in seconds for which a TOTP code is valid. Default is 30 seconds.
8
+ */
9
+ period?: number;
10
+ }
11
+
12
+ /**
13
+ * Time-based One-Time Password (TOTP) generator and verifier.
14
+ */
15
+ export class TOTP extends OTP {
16
+ /**
17
+ * The time period in seconds for which a TOTP code is valid. Default is 30 seconds.
18
+ */
19
+ period?: number;
20
+
21
+ constructor(options?: TOTPOptions) {
22
+ super(options);
23
+ this.period = options?.period || DefaultPeriod;
24
+ }
25
+
26
+ /**
27
+ * Generates a TOTP code for the given secret and time.
28
+ *
29
+ * @param secret The shared secret key used for generating the TOTP code.
30
+ * @param time The specific time (in seconds since epoch) for which to generate the TOTP code.
31
+ * If not provided, the current time will be used.
32
+ * @returns The generated TOTP code as a string.
33
+ */
34
+ async generate(secret: string, time?: number): Promise<string> {
35
+ if (!time) {
36
+ time = Math.floor(Date.now() / 1000);
37
+ }
38
+ const counter = Math.floor(time / (this.period || DefaultPeriod));
39
+
40
+ return this.generateCode(secret, counter);
41
+ }
42
+
43
+ /**
44
+ * Verifies a TOTP code for the given secret and time.
45
+ *
46
+ * @param secret The shared secret key used for generating the TOTP code.
47
+ * @param token The TOTP code to verify.
48
+ * @param time The specific time (in seconds since epoch) for which to verify the TOTP code.
49
+ * If not provided, the current time will be used.
50
+ * @returns A boolean indicating whether the TOTP code is valid.
51
+ */
52
+ async verify(secret: string, token: string, time?: number): Promise<boolean> {
53
+ if (!time) {
54
+ time = Math.floor(Date.now() / 1000);
55
+ }
56
+ const counter = Math.floor(time / (this.period || DefaultPeriod));
57
+
58
+ return this.verifyCode(secret, token, counter);
59
+ }
60
+
61
+ /**
62
+ * Generates the OTP URI for provisioning.
63
+ *
64
+ * @param secret The shared secret key used for generating the TOTP code.
65
+ * @param accountName The account name (e.g., user email) to be included in the URI.
66
+ * @returns The generated OTP URI as a string.
67
+ */
68
+ getURI(secret: string, accountName: string): string {
69
+ const params: Record<string, string | number> = {};
70
+
71
+ if (this.period && this.period !== DefaultPeriod) {
72
+ params['period'] = this.period;
73
+ }
74
+
75
+ return this.buildURI('totp', secret, accountName, params);
76
+ }
77
+ }
package/src/utils.ts ADDED
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Encodes a string into a Uint8Array using UTF-8 encoding.
3
+ *
4
+ * @param str The string to encode.
5
+ * @returns The encoded Uint8Array.
6
+ */
7
+ export const encodeString = (str: string): Uint8Array => {
8
+ return new TextEncoder().encode(str);
9
+ };
@@ -0,0 +1,88 @@
1
+ import { HOTP } from '../src/index';
2
+
3
+ describe('test HOTP generate', () => {
4
+ test('test HOTP SHA1', async () => {
5
+ const secret = '12345678901234567890';
6
+ const hotp = new HOTP({ digits: 6, algorithm: 'SHA1' });
7
+
8
+ let code = await hotp.generate(secret, 0);
9
+ expect(code).toBe('755224');
10
+
11
+ code = await hotp.generate(secret, 1);
12
+ expect(code).toBe('287082');
13
+
14
+ code = await hotp.generate(secret, 2);
15
+ expect(code).toBe('359152');
16
+
17
+ code = await hotp.generate(secret, 3);
18
+ expect(code).toBe('969429');
19
+
20
+ code = await hotp.generate(secret, 4);
21
+ expect(code).toBe('338314');
22
+
23
+ code = await hotp.generate(secret, 5);
24
+ expect(code).toBe('254676');
25
+
26
+ code = await hotp.generate(secret, 6);
27
+ expect(code).toBe('287922');
28
+
29
+ code = await hotp.generate(secret, 7);
30
+ expect(code).toBe('162583');
31
+
32
+ code = await hotp.generate(secret, 8);
33
+ expect(code).toBe('399871');
34
+
35
+ code = await hotp.generate(secret, 9);
36
+ expect(code).toBe('520489');
37
+ });
38
+ });
39
+
40
+ describe('test HOTP verify', () => {
41
+ test('test HOTP SHA1 verify', async () => {
42
+ const secret = '12345678901234567890';
43
+ const hotp = new HOTP({ digits: 6, algorithm: 'SHA1' });
44
+
45
+ const isValid0 = await hotp.verify(secret, '755224', 0);
46
+ expect(isValid0).toBe(true);
47
+
48
+ const isValid1 = await hotp.verify(secret, '287082', 1);
49
+ expect(isValid1).toBe(true);
50
+
51
+ const isValid2 = await hotp.verify(secret, '359152', 2);
52
+ expect(isValid2).toBe(true);
53
+
54
+ const isValid3 = await hotp.verify(secret, '969429', 3);
55
+ expect(isValid3).toBe(true);
56
+
57
+ const isValid4 = await hotp.verify(secret, '338314', 4);
58
+ expect(isValid4).toBe(true);
59
+
60
+ const isValid5 = await hotp.verify(secret, '254676', 5);
61
+ expect(isValid5).toBe(true);
62
+
63
+ const isValid6 = await hotp.verify(secret, '287922', 6);
64
+ expect(isValid6).toBe(true);
65
+
66
+ const isValid7 = await hotp.verify(secret, '162583', 7);
67
+ expect(isValid7).toBe(true);
68
+
69
+ const isValid8 = await hotp.verify(secret, '399871', 8);
70
+ expect(isValid8).toBe(true);
71
+
72
+ const isValid9 = await hotp.verify(secret, '520489', 9);
73
+ expect(isValid9).toBe(true);
74
+ });
75
+ });
76
+
77
+ describe('test HOTP URI generation', () => {
78
+ test('test HOTP URI', () => {
79
+ const hotp = new HOTP({ issuer: 'ExampleIssuer' });
80
+ const secret = '12345678901234567890';
81
+
82
+ let uri = hotp.getURI(secret, 'user@example.com');
83
+ expect(uri).toBe('otpauth://hotp/ExampleIssuer:user%40example.com?secret=GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ&issuer=ExampleIssuer');
84
+
85
+ uri = hotp.getURI(secret, 'user@example.com', 0);
86
+ expect(uri).toBe('otpauth://hotp/ExampleIssuer:user%40example.com?secret=GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ&issuer=ExampleIssuer&counter=0');
87
+ });
88
+ });
@@ -0,0 +1,174 @@
1
+ import { TOTP } from '../src/index';
2
+
3
+ describe('test TOTP generate', () => {
4
+ test('test TOTP SHA1', async () => {
5
+ const secret = '12345678901234567890';
6
+ const totp = new TOTP({ digits: 8, algorithm: 'SHA1' });
7
+
8
+ let code = await totp.generate(secret, 59);
9
+ expect(code).toBe('94287082');
10
+
11
+ code = await totp.generate(secret, 1111111109);
12
+ expect(code).toBe('07081804');
13
+
14
+ code = await totp.generate(secret, 1111111111);
15
+ expect(code).toBe('14050471');
16
+
17
+ code = await totp.generate(secret, 1234567890);
18
+ expect(code).toBe('89005924');
19
+
20
+ code = await totp.generate(secret, 2000000000);
21
+ expect(code).toBe('69279037');
22
+
23
+ code = await totp.generate(secret, 20000000000);
24
+ expect(code).toBe('65353130');
25
+ });
26
+
27
+ test('test TOTP SHA256', async () => {
28
+ const secret = '12345678901234567890123456789012';
29
+ const totp = new TOTP({ digits: 8, algorithm: 'SHA256' });
30
+
31
+ let code = await totp.generate(secret, 59);
32
+ expect(code).toBe('46119246');
33
+
34
+ code = await totp.generate(secret, 1111111109);
35
+ expect(code).toBe('68084774');
36
+
37
+ code = await totp.generate(secret, 1111111111);
38
+ expect(code).toBe('67062674');
39
+
40
+ code = await totp.generate(secret, 1234567890);
41
+ expect(code).toBe('91819424');
42
+
43
+ code = await totp.generate(secret, 2000000000);
44
+ expect(code).toBe('90698825');
45
+
46
+ code = await totp.generate(secret, 20000000000);
47
+ expect(code).toBe('77737706');
48
+ });
49
+
50
+ test('test TOTP SHA512', async () => {
51
+ const secret = '1234567890123456789012345678901234567890123456789012345678901234';
52
+ const totp = new TOTP({ digits: 8, algorithm: 'SHA512' });
53
+
54
+ let code = await totp.generate(secret, 59);
55
+ expect(code).toBe('90693936');
56
+
57
+ code = await totp.generate(secret, 1111111109);
58
+ expect(code).toBe('25091201');
59
+
60
+ code = await totp.generate(secret, 1111111111);
61
+ expect(code).toBe('99943326');
62
+
63
+ code = await totp.generate(secret, 1234567890);
64
+ expect(code).toBe('93441116');
65
+
66
+ code = await totp.generate(secret, 2000000000);
67
+ expect(code).toBe('38618901');
68
+
69
+ code = await totp.generate(secret, 20000000000);
70
+ expect(code).toBe('47863826');
71
+ });
72
+
73
+ test('test TOTP with current time', async () => {
74
+ // This test case may fail if the code generation crosses a time step boundary.
75
+ const totp = new TOTP();
76
+
77
+ const secret = '12345678901234567890';
78
+
79
+ const code = await totp.generate(secret);
80
+ expect(code).toHaveLength(6);
81
+
82
+ const isValid = await totp.verify(secret, code);
83
+ expect(isValid).toBe(true);
84
+ });
85
+ });
86
+
87
+ describe('test TOTP verify', () => {
88
+ test('test TOTP verify SHA1', async () => {
89
+ const secret = '12345678901234567890';
90
+ const totp = new TOTP({ digits: 8, algorithm: 'SHA1' });
91
+
92
+ let isValid = await totp.verify(secret, '94287082', 59);
93
+ expect(isValid).toBe(true);
94
+
95
+ isValid = await totp.verify(secret, '07081804', 1111111109);
96
+ expect(isValid).toBe(true);
97
+
98
+ isValid = await totp.verify(secret, '14050471', 1111111111);
99
+ expect(isValid).toBe(true);
100
+
101
+ isValid = await totp.verify(secret, '89005924', 1234567890);
102
+ expect(isValid).toBe(true);
103
+
104
+ isValid = await totp.verify(secret, '69279037', 2000000000);
105
+ expect(isValid).toBe(true);
106
+
107
+ isValid = await totp.verify(secret, '65353130', 20000000000);
108
+ expect(isValid).toBe(true);
109
+ });
110
+
111
+ test('test TOTP verify SHA256', async () => {
112
+ const secret = '12345678901234567890123456789012';
113
+ const totp = new TOTP({ digits: 8, algorithm: 'SHA256' });
114
+
115
+ let isValid = await totp.verify(secret, '46119246', 59);
116
+ expect(isValid).toBe(true);
117
+
118
+ isValid = await totp.verify(secret, '68084774', 1111111109);
119
+ expect(isValid).toBe(true);
120
+
121
+ isValid = await totp.verify(secret, '67062674', 1111111111);
122
+ expect(isValid).toBe(true);
123
+
124
+ isValid = await totp.verify(secret, '91819424', 1234567890);
125
+ expect(isValid).toBe(true);
126
+
127
+ isValid = await totp.verify(secret, '90698825', 2000000000);
128
+ expect(isValid).toBe(true);
129
+
130
+ isValid = await totp.verify(secret, '77737706', 20000000000);
131
+ expect(isValid).toBe(true);
132
+ });
133
+
134
+ test('test TOTP verify SHA512', async () => {
135
+ const secret = '1234567890123456789012345678901234567890123456789012345678901234';
136
+ const totp = new TOTP({ digits: 8, algorithm: 'SHA512' });
137
+
138
+ let isValid = await totp.verify(secret, '90693936', 59);
139
+ expect(isValid).toBe(true);
140
+
141
+ isValid = await totp.verify(secret, '25091201', 1111111109);
142
+ expect(isValid).toBe(true);
143
+
144
+ isValid = await totp.verify(secret, '99943326', 1111111111);
145
+ expect(isValid).toBe(true);
146
+
147
+ isValid = await totp.verify(secret, '93441116', 1234567890);
148
+ expect(isValid).toBe(true);
149
+
150
+ isValid = await totp.verify(secret, '38618901', 2000000000);
151
+ expect(isValid).toBe(true);
152
+
153
+ isValid = await totp.verify(secret, '47863826', 20000000000);
154
+ expect(isValid).toBe(true);
155
+ });
156
+ });
157
+
158
+ describe('test TOTP URI generation', () => {
159
+ test('test TOTP URI with default options', () => {
160
+ const totp = new TOTP({ digits: 6, algorithm: 'SHA1', period: 30, issuer: 'ExampleIssuer' });
161
+ const secret = '12345678901234567890';
162
+
163
+ const uri = totp.getURI(secret, 'user@example.com');
164
+ expect(uri).toBe('otpauth://totp/ExampleIssuer:user%40example.com?secret=GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ&issuer=ExampleIssuer');
165
+ });
166
+
167
+ test('test TOTP URI with custom period', () => {
168
+ const totp = new TOTP({ digits: 8, algorithm: 'SHA256', period: 60, issuer: 'ExampleIssuer' });
169
+ const secret = '12345678901234567890123456789012';
170
+
171
+ const uri = totp.getURI(secret, 'user@example.com');
172
+ expect(uri).toBe('otpauth://totp/ExampleIssuer:user%40example.com?secret=GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQGEZA&issuer=ExampleIssuer&algorithm=SHA256&digits=8&period=60');
173
+ });
174
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ // Visit https://aka.ms/tsconfig to read more about this file
3
+ "compilerOptions": {
4
+ // File Layout
5
+ "rootDir": "./src",
6
+ "outDir": "./dist",
7
+
8
+ // Environment Settings
9
+ // See also https://aka.ms/tsconfig/module
10
+ "module": "commonjs",
11
+ "target": "es2024",
12
+ "types": ["node", "jest"],
13
+ // For nodejs:
14
+ // "lib": ["esnext"],
15
+ // "types": ["node"],
16
+ // and npm install -D @types/node
17
+
18
+ // Other Outputs
19
+ "sourceMap": true,
20
+ "declaration": true,
21
+ "declarationMap": true,
22
+
23
+ // Stricter Typechecking Options
24
+ "noUncheckedIndexedAccess": true,
25
+ "exactOptionalPropertyTypes": true,
26
+
27
+ // Style Options
28
+ // "noImplicitReturns": true,
29
+ // "noImplicitOverride": true,
30
+ // "noUnusedLocals": true,
31
+ // "noUnusedParameters": true,
32
+ // "noFallthroughCasesInSwitch": true,
33
+ // "noPropertyAccessFromIndexSignature": true,
34
+
35
+ // Recommended Options
36
+ "strict": true,
37
+ "noUncheckedSideEffectImports": true,
38
+ "moduleDetection": "force",
39
+ "skipLibCheck": true,
40
+ },
41
+ "include": ["src"]
42
+ }