@mhmdhammoud/meritt-utils 1.6.1 → 1.6.3
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/ReleaseNotes.md +17 -1
- package/dist/__tests__/elastic-transport.test.d.ts +1 -0
- package/dist/__tests__/elastic-transport.test.js +78 -0
- package/dist/__tests__/logger.test.js +21 -0
- package/dist/lib/elastic-transport.d.ts +5 -1
- package/dist/lib/elastic-transport.js +49 -11
- package/dist/lib/logger.js +11 -6
- package/dist/types/logger.d.ts +2 -1
- package/package.json +9 -3
- package/.github/workflows/npm-publish.yml +0 -84
- package/.github/workflows/push.yml +0 -83
- package/.husky/pre-commit +0 -62
- package/.prettierrc +0 -8
- package/.prettierrc.json +0 -8
- package/ISSUES.md +0 -0
- package/eslint.config.mjs +0 -64
- package/example.env +0 -6
- package/jest.config.js +0 -13
- package/src/__tests__/colorful.test.ts +0 -77
- package/src/__tests__/formatter.test.ts +0 -96
- package/src/__tests__/logger.test.ts +0 -122
- package/src/env.d.ts +0 -9
- package/src/index.ts +0 -1
- package/src/lib/colorful.ts +0 -167
- package/src/lib/cypto.ts +0 -296
- package/src/lib/elastic-transport.ts +0 -307
- package/src/lib/formatter.ts +0 -125
- package/src/lib/imagefull.ts +0 -41
- package/src/lib/index.ts +0 -12
- package/src/lib/logger.ts +0 -590
- package/src/lib/pdf.ts +0 -25
- package/src/lib/trace-store.ts +0 -46
- package/src/types/index.ts +0 -1
- package/src/types/logger.ts +0 -66
- package/src/utilities/axios.ts +0 -4
- package/src/utilities/index.ts +0 -1
- package/tsconfig.json +0 -16
package/ReleaseNotes.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changes
|
|
2
2
|
|
|
3
|
+
## Version 1.6.3
|
|
4
|
+
|
|
5
|
+
### Elasticsearch Proxy Logging Fix
|
|
6
|
+
|
|
7
|
+
- Disabled Elasticsearch node sniffing by default. Sniffing is unsafe when the
|
|
8
|
+
configured endpoint is an HTTPS proxy because discovered nodes may advertise
|
|
9
|
+
internal addresses or a different protocol.
|
|
10
|
+
- Preserved explicit opt-in through `sniffOnConnectionFault: true` for direct
|
|
11
|
+
multi-node Elasticsearch deployments.
|
|
12
|
+
- Sanitized dots and whitespace from recursive context field names.
|
|
13
|
+
- Replaced empty context field names with `unnamed_field`.
|
|
14
|
+
- Added regression coverage for proxy-safe transport configuration and context
|
|
15
|
+
field sanitization.
|
|
16
|
+
|
|
3
17
|
## Version 1.5.3
|
|
4
18
|
|
|
5
19
|
### Logger Improvements - Critical Bug Fixes & Production Reliability
|
|
@@ -34,7 +48,9 @@
|
|
|
34
48
|
- Handles `SIGTERM` and `SIGINT` signals
|
|
35
49
|
- 5-second timeout prevents hanging forever
|
|
36
50
|
- Proper async/await handling to ensure flush completes
|
|
37
|
-
- **
|
|
51
|
+
- **Node discovery**: `sniffOnConnectionFault` is available for direct
|
|
52
|
+
multi-node Elasticsearch deployments. It should remain disabled behind a
|
|
53
|
+
proxy because discovered node addresses may not be externally reachable.
|
|
38
54
|
- **Retry logic**: Configurable retry attempts with timeout for failed requests
|
|
39
55
|
|
|
40
56
|
#### Type Safety
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const elastic_transport_1 = require("../lib/elastic-transport");
|
|
4
|
+
const elasticsearch_1 = require("@elastic/elasticsearch");
|
|
5
|
+
jest.mock('@elastic/elasticsearch', () => ({
|
|
6
|
+
Client: jest.fn(),
|
|
7
|
+
}));
|
|
8
|
+
const MockedClient = elasticsearch_1.Client;
|
|
9
|
+
const writeLog = (transport, doc) => transport.write(`${JSON.stringify(doc)}\n`);
|
|
10
|
+
const waitForEvent = (emitter, eventName) => new Promise((resolve) => {
|
|
11
|
+
emitter.once(eventName, (value) => resolve(value));
|
|
12
|
+
});
|
|
13
|
+
describe('elastic transport resilience', () => {
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
jest.useRealTimers();
|
|
16
|
+
MockedClient.mockReset();
|
|
17
|
+
});
|
|
18
|
+
test('disables node sniffing by default', () => {
|
|
19
|
+
MockedClient.mockImplementation(() => ({ bulk: jest.fn() }));
|
|
20
|
+
(0, elastic_transport_1.createElasticTransport)({ index: 'logs' });
|
|
21
|
+
expect(MockedClient).toHaveBeenCalledWith(expect.objectContaining({ sniffOnConnectionFault: false }));
|
|
22
|
+
});
|
|
23
|
+
test('allows node sniffing only when explicitly enabled', () => {
|
|
24
|
+
MockedClient.mockImplementation(() => ({ bulk: jest.fn() }));
|
|
25
|
+
(0, elastic_transport_1.createElasticTransport)({
|
|
26
|
+
index: 'logs',
|
|
27
|
+
sniffOnConnectionFault: true,
|
|
28
|
+
});
|
|
29
|
+
expect(MockedClient).toHaveBeenCalledWith(expect.objectContaining({ sniffOnConnectionFault: true }));
|
|
30
|
+
});
|
|
31
|
+
test('reports bulk failures without emitting terminal stream errors', async () => {
|
|
32
|
+
const bulk = jest
|
|
33
|
+
.fn()
|
|
34
|
+
.mockRejectedValueOnce(new Error('ES unavailable'))
|
|
35
|
+
.mockResolvedValueOnce({ errors: false, items: [] });
|
|
36
|
+
MockedClient.mockImplementation(() => ({ bulk }));
|
|
37
|
+
const transport = (0, elastic_transport_1.createElasticTransport)({
|
|
38
|
+
index: 'logs',
|
|
39
|
+
flushBytes: 1,
|
|
40
|
+
flushInterval: 10000,
|
|
41
|
+
requestTimeout: 10,
|
|
42
|
+
});
|
|
43
|
+
const streamError = jest.fn();
|
|
44
|
+
transport.on('error', streamError);
|
|
45
|
+
const failed = waitForEvent(transport, 'bulkError');
|
|
46
|
+
writeLog(transport, { message: 'first' });
|
|
47
|
+
await failed;
|
|
48
|
+
const inserted = waitForEvent(transport, 'insert');
|
|
49
|
+
writeLog(transport, { message: 'second' });
|
|
50
|
+
await expect(inserted).resolves.toEqual({ successful: 1, failed: 0 });
|
|
51
|
+
expect(streamError).not.toHaveBeenCalled();
|
|
52
|
+
expect(bulk).toHaveBeenCalledTimes(2);
|
|
53
|
+
});
|
|
54
|
+
test('watchdog releases a stuck bulk request so later logs can flush', async () => {
|
|
55
|
+
jest.useFakeTimers();
|
|
56
|
+
const bulk = jest
|
|
57
|
+
.fn()
|
|
58
|
+
.mockReturnValueOnce(new Promise(() => undefined))
|
|
59
|
+
.mockResolvedValueOnce({ errors: false, items: [] });
|
|
60
|
+
MockedClient.mockImplementation(() => ({ bulk }));
|
|
61
|
+
const transport = (0, elastic_transport_1.createElasticTransport)({
|
|
62
|
+
index: 'logs',
|
|
63
|
+
flushBytes: 1,
|
|
64
|
+
flushInterval: 10000,
|
|
65
|
+
requestTimeout: 1,
|
|
66
|
+
});
|
|
67
|
+
const timedOut = waitForEvent(transport, 'bulkError');
|
|
68
|
+
writeLog(transport, { message: 'stuck' });
|
|
69
|
+
await jest.advanceTimersByTimeAsync(5001);
|
|
70
|
+
await expect(timedOut).resolves.toMatchObject({
|
|
71
|
+
message: 'Elasticsearch bulk request timed out after 5001ms',
|
|
72
|
+
});
|
|
73
|
+
const inserted = waitForEvent(transport, 'insert');
|
|
74
|
+
writeLog(transport, { message: 'recovered' });
|
|
75
|
+
await expect(inserted).resolves.toEqual({ successful: 1, failed: 0 });
|
|
76
|
+
expect(bulk).toHaveBeenCalledTimes(2);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
@@ -132,4 +132,25 @@ describe('route and format logs', () => {
|
|
|
132
132
|
_id: expect.anything(),
|
|
133
133
|
}));
|
|
134
134
|
});
|
|
135
|
+
test('sanitize empty, dotted, and whitespace context field names', () => {
|
|
136
|
+
//@ts-ignore
|
|
137
|
+
jest.spyOn(pino_1.pino, 'destination').mockReturnValue(PINO_DESTINATION);
|
|
138
|
+
//@ts-ignore
|
|
139
|
+
pino_1.pino.mockReturnValue(PINO);
|
|
140
|
+
const logger = new logger_1.default(LOGGER_NAME);
|
|
141
|
+
logger.info(LOG_EVENT, {
|
|
142
|
+
'': 'empty',
|
|
143
|
+
'field.with.dots': 'dotted',
|
|
144
|
+
' field name ': 'spaced',
|
|
145
|
+
nested: { ' ': 'nested-empty' },
|
|
146
|
+
});
|
|
147
|
+
expect(PINO.info).toHaveBeenCalledWith(expect.objectContaining({
|
|
148
|
+
context: {
|
|
149
|
+
unnamed_field: 'empty',
|
|
150
|
+
fieldwithdots: 'dotted',
|
|
151
|
+
fieldname: 'spaced',
|
|
152
|
+
nested: { unnamed_field: 'nested-empty' },
|
|
153
|
+
},
|
|
154
|
+
}));
|
|
155
|
+
});
|
|
135
156
|
});
|
|
@@ -24,4 +24,8 @@ export interface ElasticTransportOptions extends Pick<ClientOptions, 'node' | 'a
|
|
|
24
24
|
rejectUnauthorized?: boolean;
|
|
25
25
|
tls?: ClientOptions['tls'];
|
|
26
26
|
}
|
|
27
|
-
export
|
|
27
|
+
export interface ElasticTransportStream extends NodeJS.ReadWriteStream {
|
|
28
|
+
flush: () => Promise<void>;
|
|
29
|
+
close: () => Promise<void>;
|
|
30
|
+
}
|
|
31
|
+
export declare const createElasticTransport: (opts?: ElasticTransportOptions) => ElasticTransportStream;
|
|
@@ -17,6 +17,7 @@ exports.createElasticTransport = void 0;
|
|
|
17
17
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
18
18
|
const split = require('split2');
|
|
19
19
|
const elasticsearch_1 = require("@elastic/elasticsearch");
|
|
20
|
+
const createTimeoutError = (timeoutMs) => new Error(`Elasticsearch bulk request timed out after ${timeoutMs}ms`);
|
|
20
21
|
function setDateTimeString(value) {
|
|
21
22
|
if (value !== null && typeof value === 'object' && 'time' in value) {
|
|
22
23
|
const t = value.time;
|
|
@@ -34,13 +35,15 @@ function getIndexName(index, time) {
|
|
|
34
35
|
return index.replace('%{DATE}', time.substring(0, 10));
|
|
35
36
|
}
|
|
36
37
|
function createBulkSender(opts, client, splitter) {
|
|
37
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
38
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
38
39
|
const esVersion = Number((_b = (_a = opts.esVersion) !== null && _a !== void 0 ? _a : opts['es-version']) !== null && _b !== void 0 ? _b : 7);
|
|
39
40
|
const index = (_c = opts.index) !== null && _c !== void 0 ? _c : 'pino';
|
|
40
41
|
const buildIndexName = typeof index === 'function' ? index : null;
|
|
41
42
|
const opType = esVersion >= 7 ? undefined : undefined;
|
|
42
43
|
const flushBytes = (_e = (_d = opts.flushBytes) !== null && _d !== void 0 ? _d : opts['flush-bytes']) !== null && _e !== void 0 ? _e : 1000;
|
|
43
44
|
const flushInterval = (_g = (_f = opts.flushInterval) !== null && _f !== void 0 ? _f : opts['flush-interval']) !== null && _g !== void 0 ? _g : 3000;
|
|
45
|
+
const requestTimeout = (_h = opts.requestTimeout) !== null && _h !== void 0 ? _h : 30000;
|
|
46
|
+
const bulkWatchdogTimeout = requestTimeout + 5000;
|
|
44
47
|
let buffer = [];
|
|
45
48
|
let bufferedBytes = 0;
|
|
46
49
|
let timer;
|
|
@@ -100,6 +103,40 @@ function createBulkSender(opts, client, splitter) {
|
|
|
100
103
|
error.cause = cause;
|
|
101
104
|
splitter.emit('insertError', error);
|
|
102
105
|
};
|
|
106
|
+
const emitBulkError = (err) => {
|
|
107
|
+
// Do not emit the standard stream "error" event for retryable bulk
|
|
108
|
+
// failures. Some stream consumers treat it as terminal, which can leave
|
|
109
|
+
// Pino writing into a poisoned stream while the process continues running.
|
|
110
|
+
splitter.emit('bulkError', err);
|
|
111
|
+
};
|
|
112
|
+
const bulkWithWatchdog = async (operations) => {
|
|
113
|
+
let timeout;
|
|
114
|
+
const bulkPromise = client.bulk({
|
|
115
|
+
operations,
|
|
116
|
+
refresh: false,
|
|
117
|
+
timeout: `${requestTimeout}ms`,
|
|
118
|
+
});
|
|
119
|
+
try {
|
|
120
|
+
return await Promise.race([
|
|
121
|
+
bulkPromise,
|
|
122
|
+
new Promise((_, reject) => {
|
|
123
|
+
var _a;
|
|
124
|
+
timeout = setTimeout(() => {
|
|
125
|
+
reject(createTimeoutError(bulkWatchdogTimeout));
|
|
126
|
+
}, bulkWatchdogTimeout);
|
|
127
|
+
(_a = timeout.unref) === null || _a === void 0 ? void 0 : _a.call(timeout);
|
|
128
|
+
}),
|
|
129
|
+
]);
|
|
130
|
+
}
|
|
131
|
+
finally {
|
|
132
|
+
if (timeout) {
|
|
133
|
+
clearTimeout(timeout);
|
|
134
|
+
}
|
|
135
|
+
// If the watchdog wins, the original request may reject later. Consume
|
|
136
|
+
// that rejection so a stale request cannot crash the app.
|
|
137
|
+
bulkPromise.catch(() => undefined);
|
|
138
|
+
}
|
|
139
|
+
};
|
|
103
140
|
const flush = async () => {
|
|
104
141
|
var _a, _b;
|
|
105
142
|
if (isFlushing) {
|
|
@@ -116,12 +153,7 @@ function createBulkSender(opts, client, splitter) {
|
|
|
116
153
|
bufferedBytes = 0;
|
|
117
154
|
try {
|
|
118
155
|
const operations = batch.flatMap(buildOperation);
|
|
119
|
-
const
|
|
120
|
-
operations,
|
|
121
|
-
refresh: false,
|
|
122
|
-
timeout: opts.requestTimeout ? `${opts.requestTimeout}ms` : undefined,
|
|
123
|
-
});
|
|
124
|
-
const body = response;
|
|
156
|
+
const body = await bulkWithWatchdog(operations);
|
|
125
157
|
if (body.errors && Array.isArray(body.items)) {
|
|
126
158
|
body.items.forEach((item, index) => {
|
|
127
159
|
const result = Object.values(item)[0];
|
|
@@ -132,11 +164,13 @@ function createBulkSender(opts, client, splitter) {
|
|
|
132
164
|
}
|
|
133
165
|
splitter.emit('insert', {
|
|
134
166
|
successful: batch.length,
|
|
135
|
-
failed: body.errors
|
|
167
|
+
failed: body.errors
|
|
168
|
+
? ((_b = (_a = body.items) === null || _a === void 0 ? void 0 : _a.filter((item) => { var _a; return (_a = Object.values(item)[0]) === null || _a === void 0 ? void 0 : _a.error; }).length) !== null && _b !== void 0 ? _b : 0)
|
|
169
|
+
: 0,
|
|
136
170
|
});
|
|
137
171
|
}
|
|
138
172
|
catch (err) {
|
|
139
|
-
|
|
173
|
+
emitBulkError(err);
|
|
140
174
|
// Drop the failed batch instead of wedging the stream. The next log line
|
|
141
175
|
// creates a fresh bulk request and can recover without a process restart.
|
|
142
176
|
batch.forEach((doc) => emitDroppedDocument(doc, err));
|
|
@@ -170,6 +204,7 @@ function createBulkSender(opts, client, splitter) {
|
|
|
170
204
|
};
|
|
171
205
|
}
|
|
172
206
|
const createElasticTransport = (opts = {}) => {
|
|
207
|
+
var _a;
|
|
173
208
|
const splitter = split(function (line) {
|
|
174
209
|
let value;
|
|
175
210
|
try {
|
|
@@ -206,7 +241,8 @@ const createElasticTransport = (opts = {}) => {
|
|
|
206
241
|
tls: { rejectUnauthorized: opts.rejectUnauthorized, ...opts.tls },
|
|
207
242
|
maxRetries: opts.maxRetries,
|
|
208
243
|
requestTimeout: opts.requestTimeout,
|
|
209
|
-
|
|
244
|
+
// Keep the configured proxy endpoint unless callers explicitly opt in.
|
|
245
|
+
sniffOnConnectionFault: (_a = opts.sniffOnConnectionFault) !== null && _a !== void 0 ? _a : false,
|
|
210
246
|
};
|
|
211
247
|
if (opts.caFingerprint) {
|
|
212
248
|
clientOpts.caFingerprint = opts.caFingerprint;
|
|
@@ -226,11 +262,13 @@ const createElasticTransport = (opts = {}) => {
|
|
|
226
262
|
void bulkSender.close();
|
|
227
263
|
});
|
|
228
264
|
const splitterWithDestroy = splitter;
|
|
265
|
+
splitterWithDestroy.flush = bulkSender.flush;
|
|
266
|
+
splitterWithDestroy.close = bulkSender.close;
|
|
229
267
|
const originalDestroy = splitterWithDestroy.destroy.bind(splitterWithDestroy);
|
|
230
268
|
splitterWithDestroy.destroy = function (err) {
|
|
231
269
|
void bulkSender.close();
|
|
232
270
|
originalDestroy(err);
|
|
233
271
|
};
|
|
234
|
-
return
|
|
272
|
+
return splitterWithDestroy;
|
|
235
273
|
};
|
|
236
274
|
exports.createElasticTransport = createElasticTransport;
|
package/dist/lib/logger.js
CHANGED
|
@@ -59,7 +59,8 @@ const RESERVED_ES_FIELD_ALIASES = {
|
|
|
59
59
|
};
|
|
60
60
|
/** Convert arbitrary field names into ES-safe flattened keys */
|
|
61
61
|
const toSafeElasticFieldName = (key) => {
|
|
62
|
-
const
|
|
62
|
+
const cleaned = key.replace(/[.\s]+/g, '');
|
|
63
|
+
const normalized = toSnakeCase(cleaned) || 'unnamed_field';
|
|
63
64
|
const mapped = RESERVED_ES_FIELD_ALIASES[normalized];
|
|
64
65
|
if (mapped) {
|
|
65
66
|
return mapped;
|
|
@@ -219,8 +220,12 @@ function registerShutdownHandlers() {
|
|
|
219
220
|
clearTimeout(timeout);
|
|
220
221
|
resolve();
|
|
221
222
|
});
|
|
222
|
-
|
|
223
|
-
|
|
223
|
+
esTransport === null || esTransport === void 0 ? void 0 : esTransport.flush().catch((error) => {
|
|
224
|
+
console.error(`[Logger] Error flushing logs on ${signal}:`, error);
|
|
225
|
+
}).finally(() => {
|
|
226
|
+
// Now trigger stream shutdown
|
|
227
|
+
esTransport === null || esTransport === void 0 ? void 0 : esTransport.end();
|
|
228
|
+
});
|
|
224
229
|
});
|
|
225
230
|
}
|
|
226
231
|
catch (error) {
|
|
@@ -286,8 +291,8 @@ function getLogger(elasticConfig) {
|
|
|
286
291
|
// Retry configuration for connection resilience
|
|
287
292
|
maxRetries: maxRetries,
|
|
288
293
|
requestTimeout: requestTimeout,
|
|
289
|
-
//
|
|
290
|
-
sniffOnConnectionFault:
|
|
294
|
+
// Sniffing can bypass proxies and discover unreachable internal nodes.
|
|
295
|
+
sniffOnConnectionFault: false,
|
|
291
296
|
};
|
|
292
297
|
if (elasticConfig) {
|
|
293
298
|
Object.assign(esConfig, elasticConfig);
|
|
@@ -295,7 +300,7 @@ function getLogger(elasticConfig) {
|
|
|
295
300
|
// Create transport with connection lifecycle fix (pino-elasticsearch #140)
|
|
296
301
|
esTransport = (0, elastic_transport_1.createElasticTransport)(esConfig);
|
|
297
302
|
// Handle Elasticsearch connection errors
|
|
298
|
-
esTransport.on('
|
|
303
|
+
esTransport.on('bulkError', (err) => {
|
|
299
304
|
console.error('[Logger] Elasticsearch transport error:', err.message);
|
|
300
305
|
console.error('[Logger] Logs may not be reaching Kibana. Check Elasticsearch connection.');
|
|
301
306
|
});
|
package/dist/types/logger.d.ts
CHANGED
|
@@ -58,7 +58,8 @@ export interface ElasticConfig {
|
|
|
58
58
|
requestTimeout?: number;
|
|
59
59
|
/**
|
|
60
60
|
* Whether to sniff for additional Elasticsearch nodes on connection fault.
|
|
61
|
-
*
|
|
61
|
+
* Defaults to false because sniffing can bypass a proxy and discover
|
|
62
|
+
* internal node addresses that are unreachable or use a different protocol.
|
|
62
63
|
*/
|
|
63
64
|
sniffOnConnectionFault?: boolean;
|
|
64
65
|
}
|
package/package.json
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mhmdhammoud/meritt-utils",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.3",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"private": false,
|
|
7
7
|
"typings": "./dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"imagesloaded.d.ts",
|
|
11
|
+
"README.md",
|
|
12
|
+
"ReleaseNotes.md"
|
|
13
|
+
],
|
|
8
14
|
"repository": {
|
|
9
15
|
"type": "git",
|
|
10
|
-
"url": "git@github.com
|
|
16
|
+
"url": "git+ssh://git@github.com/Mhmdhammoud/meritt-utils.git"
|
|
11
17
|
},
|
|
12
18
|
"publishConfig": {
|
|
13
19
|
"access": "public"
|
|
@@ -18,7 +24,7 @@
|
|
|
18
24
|
"watch": "tsc --watch",
|
|
19
25
|
"build": "tsc",
|
|
20
26
|
"test:types": "tsc --noemit",
|
|
21
|
-
"prepare": "husky
|
|
27
|
+
"prepare": "husky",
|
|
22
28
|
"lint": "eslint src --fix",
|
|
23
29
|
"prepublish": "npm run build",
|
|
24
30
|
"test": "jest",
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
name: NPM Publish on Release
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches: [master]
|
|
6
|
-
|
|
7
|
-
jobs:
|
|
8
|
-
test:
|
|
9
|
-
runs-on: ubuntu-latest
|
|
10
|
-
steps:
|
|
11
|
-
- name: Checkout code
|
|
12
|
-
uses: actions/checkout@v4
|
|
13
|
-
|
|
14
|
-
- name: Setup Node.js
|
|
15
|
-
uses: actions/setup-node@v4
|
|
16
|
-
with:
|
|
17
|
-
node-version: '20'
|
|
18
|
-
cache: 'npm'
|
|
19
|
-
|
|
20
|
-
- name: Install dependencies
|
|
21
|
-
run: npm ci
|
|
22
|
-
|
|
23
|
-
- name: Run type check
|
|
24
|
-
run: npm run test:types
|
|
25
|
-
|
|
26
|
-
- name: Run linting
|
|
27
|
-
run: npm run lint
|
|
28
|
-
|
|
29
|
-
- name: Run tests
|
|
30
|
-
run: npm test
|
|
31
|
-
|
|
32
|
-
build:
|
|
33
|
-
needs: test
|
|
34
|
-
runs-on: ubuntu-latest
|
|
35
|
-
steps:
|
|
36
|
-
- name: Checkout code
|
|
37
|
-
uses: actions/checkout@v4
|
|
38
|
-
|
|
39
|
-
- name: Setup Node.js
|
|
40
|
-
uses: actions/setup-node@v4
|
|
41
|
-
with:
|
|
42
|
-
node-version: '20'
|
|
43
|
-
cache: 'npm'
|
|
44
|
-
|
|
45
|
-
- name: Install dependencies
|
|
46
|
-
run: npm ci
|
|
47
|
-
|
|
48
|
-
- name: Build project
|
|
49
|
-
run: npm run build
|
|
50
|
-
|
|
51
|
-
- name: Upload build artifacts
|
|
52
|
-
uses: actions/upload-artifact@v4
|
|
53
|
-
with:
|
|
54
|
-
name: dist
|
|
55
|
-
path: dist/
|
|
56
|
-
|
|
57
|
-
publish-npm:
|
|
58
|
-
needs: [test, build]
|
|
59
|
-
runs-on: ubuntu-latest
|
|
60
|
-
if: success()
|
|
61
|
-
steps:
|
|
62
|
-
- name: Checkout code
|
|
63
|
-
uses: actions/checkout@v4
|
|
64
|
-
|
|
65
|
-
- name: Setup Node.js
|
|
66
|
-
uses: actions/setup-node@v4
|
|
67
|
-
with:
|
|
68
|
-
node-version: '20'
|
|
69
|
-
registry-url: https://registry.npmjs.org/
|
|
70
|
-
cache: 'npm'
|
|
71
|
-
|
|
72
|
-
- name: Install dependencies
|
|
73
|
-
run: npm ci
|
|
74
|
-
|
|
75
|
-
- name: Download build artifacts
|
|
76
|
-
uses: actions/download-artifact@v4
|
|
77
|
-
with:
|
|
78
|
-
name: dist
|
|
79
|
-
path: dist/
|
|
80
|
-
|
|
81
|
-
- name: Publish to NPM
|
|
82
|
-
run: npm publish
|
|
83
|
-
env:
|
|
84
|
-
NODE_AUTH_TOKEN: ${{ secrets.npm_token }}
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
name: CI Pipeline
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches: [dev]
|
|
6
|
-
pull_request:
|
|
7
|
-
branches: [dev, master]
|
|
8
|
-
|
|
9
|
-
jobs:
|
|
10
|
-
lint-and-test:
|
|
11
|
-
runs-on: ubuntu-latest
|
|
12
|
-
steps:
|
|
13
|
-
- name: Checkout code
|
|
14
|
-
uses: actions/checkout@v4
|
|
15
|
-
|
|
16
|
-
- name: Setup Node.js
|
|
17
|
-
uses: actions/setup-node@v4
|
|
18
|
-
with:
|
|
19
|
-
node-version: '20'
|
|
20
|
-
cache: 'npm'
|
|
21
|
-
|
|
22
|
-
- name: Install dependencies
|
|
23
|
-
run: npm ci
|
|
24
|
-
|
|
25
|
-
- name: Run type check
|
|
26
|
-
run: npm run test:types
|
|
27
|
-
|
|
28
|
-
- name: Run linting
|
|
29
|
-
run: npm run lint
|
|
30
|
-
|
|
31
|
-
- name: Run tests with coverage
|
|
32
|
-
run: npm run test:coverage
|
|
33
|
-
|
|
34
|
-
- name: Upload coverage reports
|
|
35
|
-
uses: actions/upload-artifact@v4
|
|
36
|
-
if: always()
|
|
37
|
-
with:
|
|
38
|
-
name: coverage-report
|
|
39
|
-
path: coverage/
|
|
40
|
-
|
|
41
|
-
build:
|
|
42
|
-
needs: lint-and-test
|
|
43
|
-
runs-on: ubuntu-latest
|
|
44
|
-
steps:
|
|
45
|
-
- name: Checkout code
|
|
46
|
-
uses: actions/checkout@v4
|
|
47
|
-
|
|
48
|
-
- name: Setup Node.js
|
|
49
|
-
uses: actions/setup-node@v4
|
|
50
|
-
with:
|
|
51
|
-
node-version: '20'
|
|
52
|
-
cache: 'npm'
|
|
53
|
-
|
|
54
|
-
- name: Install dependencies
|
|
55
|
-
run: npm ci
|
|
56
|
-
|
|
57
|
-
- name: Build project
|
|
58
|
-
run: npm run build
|
|
59
|
-
|
|
60
|
-
- name: Upload build artifacts
|
|
61
|
-
uses: actions/upload-artifact@v4
|
|
62
|
-
with:
|
|
63
|
-
name: dist
|
|
64
|
-
path: dist/
|
|
65
|
-
|
|
66
|
-
security-audit:
|
|
67
|
-
runs-on: ubuntu-latest
|
|
68
|
-
steps:
|
|
69
|
-
- name: Checkout code
|
|
70
|
-
uses: actions/checkout@v4
|
|
71
|
-
|
|
72
|
-
- name: Setup Node.js
|
|
73
|
-
uses: actions/setup-node@v4
|
|
74
|
-
with:
|
|
75
|
-
node-version: '20'
|
|
76
|
-
cache: 'npm'
|
|
77
|
-
|
|
78
|
-
- name: Install dependencies
|
|
79
|
-
run: npm ci
|
|
80
|
-
|
|
81
|
-
- name: Run security audit
|
|
82
|
-
run: npm audit --audit-level=moderate
|
|
83
|
-
|
package/.husky/pre-commit
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env sh
|
|
2
|
-
. "$(dirname -- "$0")/_/husky.sh"
|
|
3
|
-
|
|
4
|
-
red='\033[0;31m'
|
|
5
|
-
green='\033[0;32m'
|
|
6
|
-
yellow='\033[0;33m'
|
|
7
|
-
blue='\033[0;34m'
|
|
8
|
-
magenta='\033[0;35m'
|
|
9
|
-
cyan='\033[0;36m'
|
|
10
|
-
clear='\033[0m'
|
|
11
|
-
echo "
|
|
12
|
-
|
|
13
|
-
__ __ ______ _____ _____ _______ _______ _____ ________ __
|
|
14
|
-
| \/ | ____| __ \|_ _|__ __|__ __| | __ \| ____\ \ / /
|
|
15
|
-
| \ / | |__ | |__) | | | | | | | | | | | |__ \ \ / /
|
|
16
|
-
| |\/| | __| | _ / | | | | | | | | | | __| \ \/ /
|
|
17
|
-
| | | | |____| | \ \ _| |_ | | | | | |__| | |____ \ /
|
|
18
|
-
|_| |_|______|_| \_\_____| |_| |_| |_____/|______| \/
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
"
|
|
22
|
-
echo -e "Let's hope you are not ${red}DUMB${clear}!"
|
|
23
|
-
|
|
24
|
-
echo -ne '\n'
|
|
25
|
-
|
|
26
|
-
echo -e "${yellow}Or Are You ??${clear}!"
|
|
27
|
-
echo -ne '\n'
|
|
28
|
-
echo -e "${yellow}Running pre-commit hook...${clear}"
|
|
29
|
-
echo -ne '\n'
|
|
30
|
-
echo -ne '\n'
|
|
31
|
-
|
|
32
|
-
echo -ne '##################### (25%)\r'
|
|
33
|
-
sleep 0.3
|
|
34
|
-
echo -ne '############################## (35%)\r'
|
|
35
|
-
sleep 0.3
|
|
36
|
-
echo -ne '###################################### (45%)\r'
|
|
37
|
-
sleep 0.3
|
|
38
|
-
echo -ne '############################################################ (77%)\r'
|
|
39
|
-
sleep 0.3
|
|
40
|
-
echo -ne '################################################################## (100%)\r'
|
|
41
|
-
|
|
42
|
-
echo -ne '\n'
|
|
43
|
-
echo -ne '\n'
|
|
44
|
-
echo -ne '\n'
|
|
45
|
-
|
|
46
|
-
echo -e "${yellow}Running types...${clear}"
|
|
47
|
-
echo -ne '\n'
|
|
48
|
-
npm run test:types
|
|
49
|
-
echo -ne '\n'
|
|
50
|
-
|
|
51
|
-
echo -e "${green}types passed...${clear} ✅"
|
|
52
|
-
echo -ne '\n'
|
|
53
|
-
echo -e "${yellow}Running linting...${clear}"
|
|
54
|
-
|
|
55
|
-
npm run lint
|
|
56
|
-
echo -e "${green}linting passed...${clear} ✅"
|
|
57
|
-
|
|
58
|
-
echo -ne '\n'
|
|
59
|
-
|
|
60
|
-
echo -e "${yellow}Seems like you are a${clear} ${green}CLEVER DEVELOPER${clear} 👌"
|
|
61
|
-
echo -ne '\n'
|
|
62
|
-
echo -e "${green}GOOD TO GO${clear} 🚀🚀🚀"
|
package/.prettierrc
DELETED
package/.prettierrc.json
DELETED
package/ISSUES.md
DELETED
|
File without changes
|
package/eslint.config.mjs
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
import eslint from '@eslint/js'
|
|
3
|
-
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended'
|
|
4
|
-
import globals from 'globals'
|
|
5
|
-
import tseslint from 'typescript-eslint'
|
|
6
|
-
|
|
7
|
-
export default tseslint.config(
|
|
8
|
-
{
|
|
9
|
-
ignores: [
|
|
10
|
-
'eslint.config.mjs',
|
|
11
|
-
'dist/**',
|
|
12
|
-
'node_modules/**',
|
|
13
|
-
'coverage/**',
|
|
14
|
-
'*.d.ts',
|
|
15
|
-
],
|
|
16
|
-
},
|
|
17
|
-
eslint.configs.recommended,
|
|
18
|
-
...tseslint.configs.recommendedTypeChecked,
|
|
19
|
-
eslintPluginPrettierRecommended,
|
|
20
|
-
{
|
|
21
|
-
languageOptions: {
|
|
22
|
-
globals: {
|
|
23
|
-
...globals.node,
|
|
24
|
-
},
|
|
25
|
-
sourceType: 'module',
|
|
26
|
-
parserOptions: {
|
|
27
|
-
projectService: true,
|
|
28
|
-
tsconfigRootDir: import.meta.dirname,
|
|
29
|
-
},
|
|
30
|
-
},
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
rules: {
|
|
34
|
-
'@typescript-eslint/no-explicit-any': 'off',
|
|
35
|
-
'@typescript-eslint/no-floating-promises': 'warn',
|
|
36
|
-
'@typescript-eslint/no-unsafe-argument': 'off',
|
|
37
|
-
'@typescript-eslint/no-unsafe-assignment': 'off',
|
|
38
|
-
'@typescript-eslint/no-unsafe-return': 'off',
|
|
39
|
-
'@typescript-eslint/no-unsafe-member-access': 'off',
|
|
40
|
-
'@typescript-eslint/no-unsafe-call': 'off',
|
|
41
|
-
'@typescript-eslint/ban-ts-comment': 'off',
|
|
42
|
-
'@typescript-eslint/require-await': 'off',
|
|
43
|
-
'@typescript-eslint/await-thenable': 'off',
|
|
44
|
-
'@typescript-eslint/no-unsafe-enum-comparison': 'off',
|
|
45
|
-
'@typescript-eslint/no-base-to-string': 'off',
|
|
46
|
-
'@typescript-eslint/no-redundant-type-constituents': 'off',
|
|
47
|
-
'@typescript-eslint/no-unused-vars': [
|
|
48
|
-
'error',
|
|
49
|
-
{
|
|
50
|
-
argsIgnorePattern: '^_',
|
|
51
|
-
varsIgnorePattern: '^_',
|
|
52
|
-
},
|
|
53
|
-
],
|
|
54
|
-
'no-console': 'error',
|
|
55
|
-
'prettier/prettier': ['error', { semi: false }],
|
|
56
|
-
},
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
files: ['src/lib/logger.ts'],
|
|
60
|
-
rules: {
|
|
61
|
-
'no-console': 'off',
|
|
62
|
-
},
|
|
63
|
-
}
|
|
64
|
-
)
|