opticedge-cloud-utils 1.1.21 → 1.1.23
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/dist/{src/index.d.ts → index.d.ts} +1 -0
- package/dist/{src/index.js → index.js} +1 -0
- package/dist/logger.d.ts +8 -0
- package/dist/logger.js +53 -0
- package/package.json +1 -1
- package/src/index.ts +1 -0
- package/src/logger.ts +55 -0
- package/tests/logger.test.ts +116 -0
- package/tsconfig.json +1 -1
- package/dist/tests/auth.test.d.ts +0 -1
- package/dist/tests/auth.test.js +0 -79
- package/dist/tests/chunk.test.d.ts +0 -1
- package/dist/tests/chunk.test.js +0 -45
- package/dist/tests/db/mongo.test.d.ts +0 -1
- package/dist/tests/db/mongo.test.js +0 -43
- package/dist/tests/db/mongo2.test.d.ts +0 -1
- package/dist/tests/db/mongo2.test.js +0 -49
- package/dist/tests/db/mongo3.test.d.ts +0 -1
- package/dist/tests/db/mongo3.test.js +0 -60
- package/dist/tests/env.test.d.ts +0 -1
- package/dist/tests/env.test.js +0 -17
- package/dist/tests/number.test.d.ts +0 -1
- package/dist/tests/number.test.js +0 -30
- package/dist/tests/parser.test.d.ts +0 -1
- package/dist/tests/parser.test.js +0 -24
- package/dist/tests/pub.test.d.ts +0 -1
- package/dist/tests/pub.test.js +0 -102
- package/dist/tests/regex.test.d.ts +0 -1
- package/dist/tests/regex.test.js +0 -60
- package/dist/tests/retry.test.d.ts +0 -1
- package/dist/tests/retry.test.js +0 -339
- package/dist/tests/secrets.test.d.ts +0 -1
- package/dist/tests/secrets.test.js +0 -38
- package/dist/tests/task.test.d.ts +0 -1
- package/dist/tests/task.test.js +0 -262
- package/dist/tests/tw/utils.test.d.ts +0 -1
- package/dist/tests/tw/utils.test.js +0 -26
- package/dist/tests/tw/wallet.test.d.ts +0 -1
- package/dist/tests/tw/wallet.test.js +0 -108
- package/dist/tests/validator.d.ts +0 -1
- package/dist/tests/validator.js +0 -34
- /package/dist/{src/auth.d.ts → auth.d.ts} +0 -0
- /package/dist/{src/auth.js → auth.js} +0 -0
- /package/dist/{src/chunk.d.ts → chunk.d.ts} +0 -0
- /package/dist/{src/chunk.js → chunk.js} +0 -0
- /package/dist/{src/db → db}/mongo.d.ts +0 -0
- /package/dist/{src/db → db}/mongo.js +0 -0
- /package/dist/{src/db → db}/mongo2.d.ts +0 -0
- /package/dist/{src/db → db}/mongo2.js +0 -0
- /package/dist/{src/db → db}/mongo3.d.ts +0 -0
- /package/dist/{src/db → db}/mongo3.js +0 -0
- /package/dist/{src/env.d.ts → env.d.ts} +0 -0
- /package/dist/{src/env.js → env.js} +0 -0
- /package/dist/{src/number.d.ts → number.d.ts} +0 -0
- /package/dist/{src/number.js → number.js} +0 -0
- /package/dist/{src/parser.d.ts → parser.d.ts} +0 -0
- /package/dist/{src/parser.js → parser.js} +0 -0
- /package/dist/{src/pub.d.ts → pub.d.ts} +0 -0
- /package/dist/{src/pub.js → pub.js} +0 -0
- /package/dist/{src/regex.d.ts → regex.d.ts} +0 -0
- /package/dist/{src/regex.js → regex.js} +0 -0
- /package/dist/{src/retry.d.ts → retry.d.ts} +0 -0
- /package/dist/{src/retry.js → retry.js} +0 -0
- /package/dist/{src/secrets.d.ts → secrets.d.ts} +0 -0
- /package/dist/{src/secrets.js → secrets.js} +0 -0
- /package/dist/{src/task.d.ts → task.d.ts} +0 -0
- /package/dist/{src/task.js → task.js} +0 -0
- /package/dist/{src/tw → tw}/utils.d.ts +0 -0
- /package/dist/{src/tw → tw}/utils.js +0 -0
- /package/dist/{src/tw → tw}/wallet.d.ts +0 -0
- /package/dist/{src/tw → tw}/wallet.js +0 -0
- /package/dist/{src/validator.d.ts → validator.d.ts} +0 -0
- /package/dist/{src/validator.js → validator.js} +0 -0
|
@@ -22,6 +22,7 @@ __exportStar(require("./tw/wallet"), exports);
|
|
|
22
22
|
__exportStar(require("./auth"), exports);
|
|
23
23
|
__exportStar(require("./chunk"), exports);
|
|
24
24
|
__exportStar(require("./env"), exports);
|
|
25
|
+
__exportStar(require("./logger"), exports);
|
|
25
26
|
__exportStar(require("./number"), exports);
|
|
26
27
|
__exportStar(require("./parser"), exports);
|
|
27
28
|
__exportStar(require("./pub"), exports);
|
package/dist/logger.d.ts
ADDED
package/dist/logger.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// src/logger.ts
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.LogLevel = void 0;
|
|
5
|
+
exports.log = log;
|
|
6
|
+
var LogLevel;
|
|
7
|
+
(function (LogLevel) {
|
|
8
|
+
LogLevel["DEBUG"] = "DEBUG";
|
|
9
|
+
LogLevel["INFO"] = "INFO";
|
|
10
|
+
LogLevel["WARNING"] = "WARNING";
|
|
11
|
+
LogLevel["ERROR"] = "ERROR";
|
|
12
|
+
LogLevel["CRITICAL"] = "CRITICAL";
|
|
13
|
+
})(LogLevel || (exports.LogLevel = LogLevel = {}));
|
|
14
|
+
function log(level, message, metadata = {}) {
|
|
15
|
+
const payload = {
|
|
16
|
+
severity: level,
|
|
17
|
+
message,
|
|
18
|
+
...sanitize(metadata)
|
|
19
|
+
};
|
|
20
|
+
// IMPORTANT: must be single-line JSON for Cloud Logging
|
|
21
|
+
console.log(JSON.stringify(payload));
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Makes metadata JSON-safe:
|
|
25
|
+
* - ObjectId works automatically (mongodb@7)
|
|
26
|
+
* - Error objects become structured
|
|
27
|
+
* - BigInt becomes string
|
|
28
|
+
*/
|
|
29
|
+
function sanitize(obj) {
|
|
30
|
+
const safe = {};
|
|
31
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
32
|
+
if (value instanceof Error) {
|
|
33
|
+
safe[key] = {
|
|
34
|
+
name: value.name,
|
|
35
|
+
message: value.message,
|
|
36
|
+
stack: value.stack
|
|
37
|
+
};
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
if (typeof value === 'bigint') {
|
|
41
|
+
safe[key] = value.toString();
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
JSON.stringify(value);
|
|
46
|
+
safe[key] = value;
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
safe[key] = String(value);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return safe;
|
|
53
|
+
}
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
package/src/logger.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// src/logger.ts
|
|
2
|
+
|
|
3
|
+
export enum LogLevel {
|
|
4
|
+
DEBUG = 'DEBUG',
|
|
5
|
+
INFO = 'INFO',
|
|
6
|
+
WARNING = 'WARNING',
|
|
7
|
+
ERROR = 'ERROR',
|
|
8
|
+
CRITICAL = 'CRITICAL'
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function log(level: LogLevel, message: string, metadata: Record<string, any> = {}): void {
|
|
12
|
+
const payload = {
|
|
13
|
+
severity: level,
|
|
14
|
+
message,
|
|
15
|
+
...sanitize(metadata)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// IMPORTANT: must be single-line JSON for Cloud Logging
|
|
19
|
+
console.log(JSON.stringify(payload))
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Makes metadata JSON-safe:
|
|
24
|
+
* - ObjectId works automatically (mongodb@7)
|
|
25
|
+
* - Error objects become structured
|
|
26
|
+
* - BigInt becomes string
|
|
27
|
+
*/
|
|
28
|
+
function sanitize(obj: Record<string, any>): Record<string, any> {
|
|
29
|
+
const safe: Record<string, any> = {}
|
|
30
|
+
|
|
31
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
32
|
+
if (value instanceof Error) {
|
|
33
|
+
safe[key] = {
|
|
34
|
+
name: value.name,
|
|
35
|
+
message: value.message,
|
|
36
|
+
stack: value.stack
|
|
37
|
+
}
|
|
38
|
+
continue
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (typeof value === 'bigint') {
|
|
42
|
+
safe[key] = value.toString()
|
|
43
|
+
continue
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
JSON.stringify(value)
|
|
48
|
+
safe[key] = value
|
|
49
|
+
} catch {
|
|
50
|
+
safe[key] = String(value)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return safe
|
|
55
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { log, LogLevel } from '../src/logger'
|
|
2
|
+
import { ObjectId } from 'mongodb'
|
|
3
|
+
|
|
4
|
+
describe('logger.ts (100% coverage)', () => {
|
|
5
|
+
let consoleSpy: jest.SpyInstance
|
|
6
|
+
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
consoleSpy = jest.spyOn(console, 'log').mockImplementation(() => {})
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
afterEach(() => {
|
|
12
|
+
consoleSpy.mockRestore()
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
// ------------------------------------------------------------
|
|
16
|
+
// Basic log levels
|
|
17
|
+
// ------------------------------------------------------------
|
|
18
|
+
|
|
19
|
+
it('logs INFO correctly', () => {
|
|
20
|
+
log(LogLevel.INFO, 'Test message', { foo: 'bar' })
|
|
21
|
+
|
|
22
|
+
expect(consoleSpy).toHaveBeenCalledTimes(1)
|
|
23
|
+
|
|
24
|
+
const output = JSON.parse(consoleSpy.mock.calls[0][0])
|
|
25
|
+
expect(output).toEqual({
|
|
26
|
+
severity: 'INFO',
|
|
27
|
+
message: 'Test message',
|
|
28
|
+
foo: 'bar'
|
|
29
|
+
})
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it('logs all LogLevel values', () => {
|
|
33
|
+
for (const level of Object.values(LogLevel)) {
|
|
34
|
+
log(level, 'Level test')
|
|
35
|
+
const output = JSON.parse(consoleSpy.mock.calls.pop()?.[0])
|
|
36
|
+
expect(output.severity).toBe(level)
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
// ------------------------------------------------------------
|
|
41
|
+
// ObjectId handling
|
|
42
|
+
// ------------------------------------------------------------
|
|
43
|
+
|
|
44
|
+
it('serializes ObjectId correctly', () => {
|
|
45
|
+
const id = new ObjectId()
|
|
46
|
+
|
|
47
|
+
log(LogLevel.INFO, 'ObjectId test', { id })
|
|
48
|
+
|
|
49
|
+
const output = JSON.parse(consoleSpy.mock.calls[0][0])
|
|
50
|
+
|
|
51
|
+
expect(output.id).toBe(id.toHexString())
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
// ------------------------------------------------------------
|
|
55
|
+
// Error handling
|
|
56
|
+
// ------------------------------------------------------------
|
|
57
|
+
|
|
58
|
+
it('serializes Error objects correctly', () => {
|
|
59
|
+
const error = new Error('Boom')
|
|
60
|
+
|
|
61
|
+
log(LogLevel.ERROR, 'Error test', { error })
|
|
62
|
+
|
|
63
|
+
const output = JSON.parse(consoleSpy.mock.calls[0][0])
|
|
64
|
+
|
|
65
|
+
expect(output.error).toMatchObject({
|
|
66
|
+
name: 'Error',
|
|
67
|
+
message: 'Boom'
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
expect(output.error.stack).toBeDefined()
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
// ------------------------------------------------------------
|
|
74
|
+
// BigInt handling
|
|
75
|
+
// ------------------------------------------------------------
|
|
76
|
+
|
|
77
|
+
it('converts BigInt to string', () => {
|
|
78
|
+
const big = BigInt(123456789)
|
|
79
|
+
|
|
80
|
+
log(LogLevel.INFO, 'BigInt test', { big })
|
|
81
|
+
|
|
82
|
+
const output = JSON.parse(consoleSpy.mock.calls[0][0])
|
|
83
|
+
|
|
84
|
+
expect(output.big).toBe('123456789')
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
// ------------------------------------------------------------
|
|
88
|
+
// Fallback serialization branch
|
|
89
|
+
// ------------------------------------------------------------
|
|
90
|
+
|
|
91
|
+
it('falls back to string for unserializable values', () => {
|
|
92
|
+
const circular: any = {}
|
|
93
|
+
circular.self = circular
|
|
94
|
+
|
|
95
|
+
log(LogLevel.INFO, 'Circular test', { circular })
|
|
96
|
+
|
|
97
|
+
const output = JSON.parse(consoleSpy.mock.calls[0][0])
|
|
98
|
+
|
|
99
|
+
expect(output.circular).toBe('[object Object]')
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
// ------------------------------------------------------------
|
|
103
|
+
// No metadata case
|
|
104
|
+
// ------------------------------------------------------------
|
|
105
|
+
|
|
106
|
+
it('works without metadata', () => {
|
|
107
|
+
log(LogLevel.WARNING, 'No metadata')
|
|
108
|
+
|
|
109
|
+
const output = JSON.parse(consoleSpy.mock.calls[0][0])
|
|
110
|
+
|
|
111
|
+
expect(output).toEqual({
|
|
112
|
+
severity: 'WARNING',
|
|
113
|
+
message: 'No metadata'
|
|
114
|
+
})
|
|
115
|
+
})
|
|
116
|
+
})
|
package/tsconfig.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/tests/auth.test.js
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const auth_1 = require("../src/auth");
|
|
4
|
-
// Mock the google-auth-library
|
|
5
|
-
jest.mock('google-auth-library', () => {
|
|
6
|
-
return {
|
|
7
|
-
OAuth2Client: jest.fn().mockImplementation(() => ({
|
|
8
|
-
verifyIdToken: jest.fn(({ idToken, audience }) => {
|
|
9
|
-
if (idToken === 'valid-token' && audience === 'audience') {
|
|
10
|
-
return {
|
|
11
|
-
getPayload: () => ({
|
|
12
|
-
email: 'allowed@example.com'
|
|
13
|
-
})
|
|
14
|
-
};
|
|
15
|
-
}
|
|
16
|
-
else if (idToken === 'wrong-email-token' && audience === 'audience') {
|
|
17
|
-
return {
|
|
18
|
-
getPayload: () => ({
|
|
19
|
-
email: 'unauthorized@example.com'
|
|
20
|
-
})
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
throw new Error('Invalid token');
|
|
24
|
-
})
|
|
25
|
-
}))
|
|
26
|
-
};
|
|
27
|
-
});
|
|
28
|
-
describe('verifyRequest', () => {
|
|
29
|
-
it('returns true for valid token and matching email', async () => {
|
|
30
|
-
const mockReq = {
|
|
31
|
-
headers: {
|
|
32
|
-
authorization: 'Bearer valid-token'
|
|
33
|
-
}
|
|
34
|
-
};
|
|
35
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
36
|
-
const result = await (0, auth_1.verifyRequest)(mockReq, {
|
|
37
|
-
allowedAudience: 'audience',
|
|
38
|
-
allowedServiceAccount: 'allowed@example.com'
|
|
39
|
-
});
|
|
40
|
-
expect(result).toBe(true);
|
|
41
|
-
});
|
|
42
|
-
it('returns false for invalid token', async () => {
|
|
43
|
-
const mockReq = {
|
|
44
|
-
headers: {
|
|
45
|
-
authorization: 'Bearer invalid-token'
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
49
|
-
const result = await (0, auth_1.verifyRequest)(mockReq, {
|
|
50
|
-
allowedAudience: 'audience',
|
|
51
|
-
allowedServiceAccount: 'allowed@example.com'
|
|
52
|
-
});
|
|
53
|
-
expect(result).toBe(false);
|
|
54
|
-
});
|
|
55
|
-
it('returns false for missing authorization header', async () => {
|
|
56
|
-
const mockReq = {
|
|
57
|
-
headers: {}
|
|
58
|
-
};
|
|
59
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
60
|
-
const result = await (0, auth_1.verifyRequest)(mockReq, {
|
|
61
|
-
allowedAudience: 'audience',
|
|
62
|
-
allowedServiceAccount: 'allowed@example.com'
|
|
63
|
-
});
|
|
64
|
-
expect(result).toBe(false);
|
|
65
|
-
});
|
|
66
|
-
it('returns false for incorrect email', async () => {
|
|
67
|
-
const mockReq = {
|
|
68
|
-
headers: {
|
|
69
|
-
authorization: 'Bearer wrong-email-token'
|
|
70
|
-
}
|
|
71
|
-
};
|
|
72
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
73
|
-
const result = await (0, auth_1.verifyRequest)(mockReq, {
|
|
74
|
-
allowedAudience: 'audience',
|
|
75
|
-
allowedServiceAccount: 'allowed@example.com'
|
|
76
|
-
});
|
|
77
|
-
expect(result).toBe(false);
|
|
78
|
-
});
|
|
79
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/tests/chunk.test.js
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const chunk_1 = require("../src/chunk");
|
|
4
|
-
describe('chunkByBytes', () => {
|
|
5
|
-
test('splits array into chunks based on byte size', () => {
|
|
6
|
-
const arr = [
|
|
7
|
-
{ id: 'a', val: 'x'.repeat(100) },
|
|
8
|
-
{ id: 'b', val: 'y'.repeat(100) },
|
|
9
|
-
{ id: 'c', val: 'z'.repeat(100) }
|
|
10
|
-
];
|
|
11
|
-
const chunks = (0, chunk_1.chunkByBytes)(arr, 200); // 200 bytes max per chunk
|
|
12
|
-
expect(chunks.length).toBeGreaterThan(1); // should split
|
|
13
|
-
expect(chunks.flat()).toEqual(arr); // all items present
|
|
14
|
-
});
|
|
15
|
-
test('puts single large item in its own chunk', () => {
|
|
16
|
-
const arr = [{ id: 'big', val: 'x'.repeat(1000) }];
|
|
17
|
-
const chunks = (0, chunk_1.chunkByBytes)(arr, 100);
|
|
18
|
-
expect(chunks).toEqual([arr]); // large item pushed alone
|
|
19
|
-
});
|
|
20
|
-
test('does not split if all items fit within maxBytes', () => {
|
|
21
|
-
const arr = [
|
|
22
|
-
{ id: 'a', val: 'x' },
|
|
23
|
-
{ id: 'b', val: 'y' }
|
|
24
|
-
];
|
|
25
|
-
const chunks = (0, chunk_1.chunkByBytes)(arr, 1000);
|
|
26
|
-
expect(chunks).toEqual([arr]);
|
|
27
|
-
});
|
|
28
|
-
test('uses default maxBytes if not provided', () => {
|
|
29
|
-
const arr = [{ id: 'a', val: 'x'.repeat(10) }];
|
|
30
|
-
// call without maxBytes
|
|
31
|
-
const chunks = (0, chunk_1.chunkByBytes)(arr);
|
|
32
|
-
expect(chunks.flat()).toEqual(arr); // all items present
|
|
33
|
-
});
|
|
34
|
-
test('flushes current chunk when a single item exceeds maxBytes', () => {
|
|
35
|
-
const arr = [
|
|
36
|
-
{ id: '1', val: 'x'.repeat(50) }, // first small item
|
|
37
|
-
{ id: '2', val: 'y'.repeat(200) } // oversized item
|
|
38
|
-
];
|
|
39
|
-
// set maxBytes small enough to trigger oversized item
|
|
40
|
-
const chunks = (0, chunk_1.chunkByBytes)(arr, 100);
|
|
41
|
-
expect(chunks.length).toBe(2); // first small chunk + oversized item alone
|
|
42
|
-
expect(chunks[0]).toEqual([arr[0]]); // first item in first chunk
|
|
43
|
-
expect(chunks[1]).toEqual([arr[1]]); // second item alone
|
|
44
|
-
});
|
|
45
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const mongo_1 = require("../../src/db/mongo");
|
|
4
|
-
const mongodb_1 = require("mongodb");
|
|
5
|
-
jest.mock('mongodb');
|
|
6
|
-
const mockDb = {
|
|
7
|
-
collection: jest.fn()
|
|
8
|
-
};
|
|
9
|
-
const mockConnect = jest.fn();
|
|
10
|
-
const mockClient = {
|
|
11
|
-
connect: mockConnect,
|
|
12
|
-
db: jest.fn().mockReturnValue(mockDb)
|
|
13
|
-
};
|
|
14
|
-
beforeEach(() => {
|
|
15
|
-
jest.clearAllMocks();
|
|
16
|
-
mongodb_1.MongoClient.mockImplementation(() => mockClient);
|
|
17
|
-
});
|
|
18
|
-
describe('Mongo Utils', () => {
|
|
19
|
-
it('should connect to MongoDB and store client/db', async () => {
|
|
20
|
-
await (0, mongo_1.connectToMongo)('mongo-uri', 'test-db');
|
|
21
|
-
expect(mockConnect).toHaveBeenCalled();
|
|
22
|
-
expect(mockClient.db).toHaveBeenCalledWith('test-db');
|
|
23
|
-
});
|
|
24
|
-
it('should return a collection when db is initialized', async () => {
|
|
25
|
-
await (0, mongo_1.connectToMongo)('mongo-uri', 'test-db');
|
|
26
|
-
(0, mongo_1.getCollection)('users');
|
|
27
|
-
expect(mockDb.collection).toHaveBeenCalledWith('users');
|
|
28
|
-
});
|
|
29
|
-
it('getDb should return the initialized Db instance', async () => {
|
|
30
|
-
await (0, mongo_1.connectToMongo)('mongo-uri', 'test-db');
|
|
31
|
-
const got = (0, mongo_1.getDb)();
|
|
32
|
-
expect(got).toBe(mockDb);
|
|
33
|
-
});
|
|
34
|
-
it('should throw error if db is not initialized (getCollection/getDb)', () => {
|
|
35
|
-
jest.isolateModules(() => {
|
|
36
|
-
// require a fresh copy of the module so module-level state is uninitialized
|
|
37
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
38
|
-
const mod = require('../../src/db/mongo');
|
|
39
|
-
expect(() => mod.getCollection('users')).toThrow(/Mongo not initialized/);
|
|
40
|
-
expect(() => mod.getDb()).toThrow(/Mongo not initialized/);
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const mongo2_1 = require("../../src/db/mongo2");
|
|
4
|
-
const mongodb_1 = require("mongodb");
|
|
5
|
-
jest.mock('mongodb');
|
|
6
|
-
const mockDb = {
|
|
7
|
-
collection: jest.fn()
|
|
8
|
-
};
|
|
9
|
-
const mockConnect = jest.fn();
|
|
10
|
-
const mockClient = {
|
|
11
|
-
connect: mockConnect,
|
|
12
|
-
db: jest.fn().mockReturnValue(mockDb)
|
|
13
|
-
};
|
|
14
|
-
beforeEach(() => {
|
|
15
|
-
jest.clearAllMocks();
|
|
16
|
-
mongodb_1.MongoClient.mockImplementation(() => mockClient);
|
|
17
|
-
});
|
|
18
|
-
describe('Mongo Utils', () => {
|
|
19
|
-
it('should connect to MongoDB and store client', async () => {
|
|
20
|
-
await (0, mongo2_1.connectToMongo2)('mongo-uri');
|
|
21
|
-
expect(mockConnect).toHaveBeenCalled();
|
|
22
|
-
});
|
|
23
|
-
it('should return a Db instance when client is initialized', async () => {
|
|
24
|
-
await (0, mongo2_1.connectToMongo2)('mongo-uri');
|
|
25
|
-
const db = (0, mongo2_1.getDb2)('test-db');
|
|
26
|
-
expect(mockClient.db).toHaveBeenCalledWith('test-db');
|
|
27
|
-
expect(db).toBe(mockDb);
|
|
28
|
-
});
|
|
29
|
-
it('should return a collection when client is initialized', async () => {
|
|
30
|
-
await (0, mongo2_1.connectToMongo2)('mongo-uri');
|
|
31
|
-
(0, mongo2_1.getCollection2)('test-db', 'users');
|
|
32
|
-
expect(mockClient.db).toHaveBeenCalledWith('test-db');
|
|
33
|
-
expect(mockDb.collection).toHaveBeenCalledWith('users');
|
|
34
|
-
});
|
|
35
|
-
it('should throw error if client is not initialized (getDb)', () => {
|
|
36
|
-
jest.isolateModules(() => {
|
|
37
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
38
|
-
const { getDb2 } = require('../../src/db/mongo2');
|
|
39
|
-
expect(() => getDb2('test-db')).toThrow('Mongo not initialized');
|
|
40
|
-
});
|
|
41
|
-
});
|
|
42
|
-
it('should throw error if client is not initialized (getCollection)', () => {
|
|
43
|
-
jest.isolateModules(() => {
|
|
44
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
45
|
-
const { getCollection2 } = require('../../src/db/mongo2');
|
|
46
|
-
expect(() => getCollection2('test-db', 'users')).toThrow('Mongo not initialized');
|
|
47
|
-
});
|
|
48
|
-
});
|
|
49
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const mongo3_1 = require("../../src/db/mongo3");
|
|
4
|
-
const mongodb_1 = require("mongodb");
|
|
5
|
-
jest.mock('mongodb');
|
|
6
|
-
const mockDb = {
|
|
7
|
-
collection: jest.fn()
|
|
8
|
-
};
|
|
9
|
-
const mockConnect = jest.fn();
|
|
10
|
-
const mockClient = {
|
|
11
|
-
connect: mockConnect,
|
|
12
|
-
db: jest.fn().mockReturnValue(mockDb)
|
|
13
|
-
};
|
|
14
|
-
beforeEach(() => {
|
|
15
|
-
jest.clearAllMocks();
|
|
16
|
-
mongo3_1.__mongoClients.clear();
|
|
17
|
-
mongo3_1.__connectPromises.clear();
|
|
18
|
-
mongodb_1.MongoClient.mockImplementation(() => mockClient);
|
|
19
|
-
});
|
|
20
|
-
describe('MongoClientManager (multi-cluster)', () => {
|
|
21
|
-
const clusterAUri = 'clusterA-uri';
|
|
22
|
-
const clusterBUri = 'clusterB-uri';
|
|
23
|
-
it('should connect and cache client for a single cluster', async () => {
|
|
24
|
-
await (0, mongo3_1.connectToMongo3)(clusterAUri);
|
|
25
|
-
expect(mockConnect).toHaveBeenCalled();
|
|
26
|
-
const db = (0, mongo3_1.getDb3)(clusterAUri, 'test-db');
|
|
27
|
-
expect(mockClient.db).toHaveBeenCalledWith('test-db');
|
|
28
|
-
expect(db).toBe(mockDb);
|
|
29
|
-
});
|
|
30
|
-
it('should reuse client if already connected', async () => {
|
|
31
|
-
await (0, mongo3_1.connectToMongo3)(clusterAUri);
|
|
32
|
-
await (0, mongo3_1.connectToMongo3)(clusterAUri);
|
|
33
|
-
expect(mockConnect).toHaveBeenCalledTimes(1);
|
|
34
|
-
});
|
|
35
|
-
it('should connect and cache separate clients for multiple clusters', async () => {
|
|
36
|
-
await (0, mongo3_1.connectToMongo3)(clusterAUri);
|
|
37
|
-
await (0, mongo3_1.connectToMongo3)(clusterBUri);
|
|
38
|
-
expect(mockConnect).toHaveBeenCalledTimes(2);
|
|
39
|
-
});
|
|
40
|
-
it('should return a collection when client is initialized', async () => {
|
|
41
|
-
await (0, mongo3_1.connectToMongo3)(clusterAUri);
|
|
42
|
-
(0, mongo3_1.getCollection3)(clusterAUri, 'test-db', 'users');
|
|
43
|
-
expect(mockClient.db).toHaveBeenCalledWith('test-db');
|
|
44
|
-
expect(mockDb.collection).toHaveBeenCalledWith('users');
|
|
45
|
-
});
|
|
46
|
-
it('should throw error if client not initialized (getDb)', () => {
|
|
47
|
-
jest.isolateModules(() => {
|
|
48
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
49
|
-
const { getDb3 } = require('../../src/db/mongo3');
|
|
50
|
-
expect(() => getDb3('unknown-uri', 'some-db')).toThrow('Mongo client not initialized');
|
|
51
|
-
});
|
|
52
|
-
});
|
|
53
|
-
it('should throw error if client not initialized (getCollection)', () => {
|
|
54
|
-
jest.isolateModules(() => {
|
|
55
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
56
|
-
const { getCollection3 } = require('../../src/db/mongo3');
|
|
57
|
-
expect(() => getCollection3('unknown-uri', 'some-db', 'users')).toThrow('Mongo client not initialized');
|
|
58
|
-
});
|
|
59
|
-
});
|
|
60
|
-
});
|
package/dist/tests/env.test.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/tests/env.test.js
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const env_1 = require("../src/env");
|
|
4
|
-
describe('getEnv', () => {
|
|
5
|
-
it('returns the value of an existing env var', () => {
|
|
6
|
-
process.env.TEST_KEY = 'test-value';
|
|
7
|
-
expect((0, env_1.getEnv)('TEST_KEY')).toBe('test-value');
|
|
8
|
-
});
|
|
9
|
-
it('returns fallback if env var is not set', () => {
|
|
10
|
-
delete process.env.OPTIONAL_KEY;
|
|
11
|
-
expect((0, env_1.getEnv)('OPTIONAL_KEY', 'default')).toBe('default');
|
|
12
|
-
});
|
|
13
|
-
it('throws error if env var is not set and no fallback provided', () => {
|
|
14
|
-
delete process.env.MISSING_KEY;
|
|
15
|
-
expect(() => (0, env_1.getEnv)('MISSING_KEY')).toThrow('Missing env var MISSING_KEY');
|
|
16
|
-
});
|
|
17
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const number_1 = require("../src/number");
|
|
4
|
-
describe('round1', () => {
|
|
5
|
-
it('rounds down correctly', () => {
|
|
6
|
-
expect((0, number_1.round1)(4.21)).toBe(4.2);
|
|
7
|
-
expect((0, number_1.round1)(4.24)).toBe(4.2);
|
|
8
|
-
});
|
|
9
|
-
it('rounds up correctly', () => {
|
|
10
|
-
expect((0, number_1.round1)(4.25)).toBe(4.3);
|
|
11
|
-
expect((0, number_1.round1)(4.26)).toBe(4.3);
|
|
12
|
-
});
|
|
13
|
-
it('handles floating point precision issues', () => {
|
|
14
|
-
expect((0, number_1.round1)(1.005)).toBe(1.0); // classic float issue
|
|
15
|
-
expect((0, number_1.round1)(2.675)).toBe(2.7);
|
|
16
|
-
});
|
|
17
|
-
it('handles negative numbers', () => {
|
|
18
|
-
expect((0, number_1.round1)(-4.24)).toBe(-4.2);
|
|
19
|
-
expect((0, number_1.round1)(-4.25)).toBe(-4.2); // JS rounds toward +∞ for halves
|
|
20
|
-
expect((0, number_1.round1)(-4.26)).toBe(-4.3);
|
|
21
|
-
});
|
|
22
|
-
it('handles zero', () => {
|
|
23
|
-
expect((0, number_1.round1)(0)).toBe(0);
|
|
24
|
-
expect((0, number_1.round1)(0.04)).toBe(0);
|
|
25
|
-
expect((0, number_1.round1)(0.05)).toBe(0.1);
|
|
26
|
-
});
|
|
27
|
-
it('handles large numbers', () => {
|
|
28
|
-
expect((0, number_1.round1)(123456.789)).toBe(123456.8);
|
|
29
|
-
});
|
|
30
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const src_1 = require("../src");
|
|
4
|
-
describe('toNumber', () => {
|
|
5
|
-
it('returns the same number when input is a finite number', () => {
|
|
6
|
-
expect((0, src_1.toNumber)(123)).toBe(123);
|
|
7
|
-
expect((0, src_1.toNumber)(0)).toBe(0);
|
|
8
|
-
});
|
|
9
|
-
it('returns number when input is a numeric string', () => {
|
|
10
|
-
expect((0, src_1.toNumber)('456')).toBe(456);
|
|
11
|
-
});
|
|
12
|
-
it('returns null for non-numeric strings', () => {
|
|
13
|
-
expect((0, src_1.toNumber)('abc')).toBeNull();
|
|
14
|
-
expect((0, src_1.toNumber)('123abc')).toBeNull();
|
|
15
|
-
expect((0, src_1.toNumber)('')).toBeNull();
|
|
16
|
-
});
|
|
17
|
-
it('returns null for non-numbers', () => {
|
|
18
|
-
expect((0, src_1.toNumber)(NaN)).toBeNull();
|
|
19
|
-
expect((0, src_1.toNumber)(Infinity)).toBeNull();
|
|
20
|
-
expect((0, src_1.toNumber)(undefined)).toBeNull();
|
|
21
|
-
expect((0, src_1.toNumber)(null)).toBeNull();
|
|
22
|
-
expect((0, src_1.toNumber)({})).toBeNull();
|
|
23
|
-
});
|
|
24
|
-
});
|
package/dist/tests/pub.test.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
declare const path = "../src/pub";
|