@quartz-labs/logger 1.0.0 → 1.0.1

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.
@@ -0,0 +1,9 @@
1
+ declare const config: {
2
+ EMAIL_TO: string[];
3
+ EMAIL_FROM: string;
4
+ EMAIL_HOST: string;
5
+ EMAIL_PORT: number;
6
+ EMAIL_USER: string;
7
+ EMAIL_PASSWORD: string;
8
+ };
9
+ export default config;
@@ -1,26 +1,25 @@
1
1
  import dotenv from 'dotenv';
2
2
  import { z } from 'zod';
3
-
4
3
  dotenv.config();
5
-
6
4
  const envSchema = z.object({
7
5
  EMAIL_TO: z.string()
8
6
  .transform((str) => {
9
- try {
10
- const emails = str.split(',').map(email => email.trim());
11
- if (!emails.every(email => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email))) throw new Error();
12
- return emails;
13
- } catch {
14
- throw new Error("Invalid email list format: must be comma-separated email addresses");
15
- }
16
- }),
7
+ try {
8
+ const emails = str.split(',').map(email => email.trim());
9
+ if (!emails.every(email => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)))
10
+ throw new Error();
11
+ return emails;
12
+ }
13
+ catch {
14
+ throw new Error("Invalid email list format: must be comma-separated email addresses");
15
+ }
16
+ }),
17
17
  EMAIL_FROM: z.string().email(),
18
18
  EMAIL_HOST: z.string(),
19
19
  EMAIL_PORT: z.coerce.number().min(0),
20
20
  EMAIL_USER: z.string().email(),
21
21
  EMAIL_PASSWORD: z.string(),
22
22
  });
23
-
24
23
  const config = envSchema.parse({
25
24
  EMAIL_TO: process.env.EMAIL_TO,
26
25
  EMAIL_FROM: process.env.EMAIL_FROM,
@@ -29,5 +28,5 @@ const config = envSchema.parse({
29
28
  EMAIL_USER: process.env.EMAIL_USER,
30
29
  EMAIL_PASSWORD: process.env.EMAIL_PASSWORD,
31
30
  });
32
-
33
31
  export default config;
32
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,EAAE,CAAC;AAEhB,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC;IACvB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;SACf,SAAS,CAAC,CAAC,GAAG,EAAE,EAAE;QACf,IAAI,CAAC;YACD,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;YACzD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,4BAA4B,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBAAE,MAAM,IAAI,KAAK,EAAE,CAAC;YACxF,OAAO,MAAM,CAAC;QAClB,CAAC;QAAC,MAAM,CAAC;YACL,MAAM,IAAI,KAAK,CAAC,oEAAoE,CAAC,CAAC;QAC1F,CAAC;IACL,CAAC,CAAC;IACN,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE;IAC9B,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE;IACtB,UAAU,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACpC,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE;IAC9B,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE;CAC7B,CAAC,CAAC;AAEH,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,CAAC;IAC3B,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ;IAC9B,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU;IAClC,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU;IAClC,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU;IAClC,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU;IAClC,cAAc,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc;CAC7C,CAAC,CAAC;AAEH,eAAe,MAAM,CAAC"}
@@ -0,0 +1 @@
1
+ export { AppLogger } from "./logger.js";
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { AppLogger } from "./logger.js";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { type Logger } from "winston";
2
+ export interface AppLoggerOptions {
3
+ name: string;
4
+ dailyErrorCacheTimeMs: number;
5
+ }
6
+ export declare class AppLogger {
7
+ protected logger: Logger;
8
+ private dailyErrorCache;
9
+ private dailyErrorCacheTimeMs;
10
+ constructor(options: AppLoggerOptions);
11
+ }
@@ -1,37 +1,21 @@
1
1
  import { Writable } from "node:stream";
2
- import winston, { createLogger, type Logger, transports } from "winston";
2
+ import winston, { createLogger, transports } from "winston";
3
3
  import nodemailer from "nodemailer";
4
4
  import config from "./config.js";
5
- import type { ErrorCacheEntry } from "./types/ErrorCacheEntry.interface.js";
6
-
7
- export interface AppLoggerOptions {
8
- name: string;
9
- dailyErrorCacheTimeMs: number;
10
- }
11
-
12
5
  export class AppLogger {
13
- protected logger: Logger;
14
- private dailyErrorCache = new Map<string, ErrorCacheEntry>();
6
+ logger;
7
+ dailyErrorCache = new Map();
15
8
  // TODO: Clear cache once a day
16
- private dailyErrorCacheTimeMs: number;
17
-
18
- constructor(options: AppLoggerOptions) {
19
- if (options.dailyErrorCacheTimeMs < 0) this.dailyErrorCacheTimeMs = 0;
20
- else this.dailyErrorCacheTimeMs = options.dailyErrorCacheTimeMs;
21
-
22
- const consoleFormat = winston.format.combine(
23
- winston.format.colorize(),
24
- winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
25
- winston.format.printf(({ level, message, timestamp }) => {
26
- return `[${timestamp}] ${level}: ${message}`;
27
- })
28
- )
29
-
30
- const mailFormat = winston.format.combine(
31
- winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
32
- winston.format.json({ space: 2})
33
- )
34
-
9
+ dailyErrorCacheTimeMs;
10
+ constructor(options) {
11
+ if (options.dailyErrorCacheTimeMs < 0)
12
+ this.dailyErrorCacheTimeMs = 0;
13
+ else
14
+ this.dailyErrorCacheTimeMs = options.dailyErrorCacheTimeMs;
15
+ const consoleFormat = winston.format.combine(winston.format.colorize(), winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), winston.format.printf(({ level, message, timestamp }) => {
16
+ return `[${timestamp}] ${level}: ${message}`;
17
+ }));
18
+ const mailFormat = winston.format.combine(winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), winston.format.json({ space: 2 }));
35
19
  const mailTransporter = nodemailer.createTransport({
36
20
  host: config.EMAIL_HOST,
37
21
  port: config.EMAIL_PORT,
@@ -41,24 +25,20 @@ export class AppLogger {
41
25
  pass: config.EMAIL_PASSWORD,
42
26
  },
43
27
  });
44
-
45
28
  const dailyErrorCacheTimeMinutes = Math.round(this.dailyErrorCacheTimeMs / 1000 / 60);
46
29
  const mailTransportInstance = new winston.transports.Stream({
47
30
  stream: new Writable({
48
31
  write: (message, _, callback) => {
49
32
  const parsedMessage = JSON.parse(message);
50
33
  const cacheKey = `${parsedMessage.level}: ${parsedMessage.message}`;
51
-
52
34
  const now = Date.now();
53
35
  const cacheEntry = this.dailyErrorCache.get(cacheKey) || { count: 0, lastSent: 0 };
54
36
  cacheEntry.count++;
55
-
56
37
  // Only send email if error has not been sent in the last errorEmailCacheTime seconds
57
38
  if (now - cacheEntry.lastSent > this.dailyErrorCacheTimeMs) {
58
39
  const emailSubject = this.dailyErrorCacheTimeMs > 0
59
40
  ? `${options.name} Error (${cacheEntry.count} occurrences in past ${dailyErrorCacheTimeMinutes} minutes)`
60
41
  : `${options.name} Error`;
61
-
62
42
  for (const admin of config.EMAIL_TO) {
63
43
  mailTransporter.sendMail({
64
44
  from: config.EMAIL_FROM,
@@ -69,13 +49,10 @@ export class AppLogger {
69
49
  console.error("Failed to send error email: ", error);
70
50
  });
71
51
  }
72
-
73
52
  cacheEntry.count = 0;
74
53
  cacheEntry.lastSent = now;
75
54
  }
76
-
77
55
  this.dailyErrorCache.set(cacheKey, cacheEntry);
78
-
79
56
  callback();
80
57
  return true;
81
58
  }
@@ -83,7 +60,6 @@ export class AppLogger {
83
60
  level: 'error',
84
61
  format: mailFormat,
85
62
  });
86
-
87
63
  this.logger = createLogger({
88
64
  level: 'info',
89
65
  transports: [
@@ -99,13 +75,12 @@ export class AppLogger {
99
75
  mailTransportInstance
100
76
  ],
101
77
  });
102
-
103
78
  process.on("uncaughtException", (error) => {
104
79
  this.logger.error(error.message);
105
80
  });
106
-
107
81
  process.on("unhandledRejection", (reason) => {
108
82
  this.logger.error(reason);
109
83
  });
110
84
  }
111
- }
85
+ }
86
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
1
  export interface ErrorCacheEntry {
2
2
  lastSent: number;
3
3
  count: number;
4
- }
4
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ErrorCacheEntry.interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ErrorCacheEntry.interface.js","sourceRoot":"","sources":["../../src/types/ErrorCacheEntry.interface.ts"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -1,8 +1,20 @@
1
1
  {
2
2
  "name": "@quartz-labs/logger",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Logger class for outputting logs and emailing any errors to admins",
5
- "main": "index.js",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "module": "dist/index.js",
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "exports": {
12
+ "*": {
13
+ "import": "./dist/index.js",
14
+ "require": "./dist/index.js",
15
+ "types": "./dist/index.d.ts"
16
+ }
17
+ },
6
18
  "type": "module",
7
19
  "repository": "https://github.com/quartz-labs/logger.git",
8
20
  "author": "Quartz Labs",
package/src/index.ts DELETED
@@ -1 +0,0 @@
1
- export { AppLogger } from "./logger.js";
package/tsconfig.json DELETED
@@ -1,21 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "esModuleInterop": true,
4
- "skipLibCheck": true,
5
- "target": "es2022",
6
- "allowJs": true,
7
- "resolveJsonModule": true,
8
- "moduleDetection": "force",
9
- "isolatedModules": true,
10
- "verbatimModuleSyntax": true,
11
- "strict": true,
12
- "noUncheckedIndexedAccess": true,
13
- "noImplicitOverride": true,
14
- "module": "NodeNext",
15
- "outDir": "dist",
16
- "rootDir": "src",
17
- "sourceMap": true,
18
- "declaration": true,
19
- "lib": ["es2022"],
20
- }
21
- }