@kava/kava-api-core 1.0.0 → 1.0.2
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/.github/workflows/publish.yml +40 -0
- package/dist/{auth.util.d.ts → auth/auth.d.ts} +1 -5
- package/dist/{auth.util.js → auth/auth.js} +38 -30
- package/dist/auth/auth.js.map +1 -0
- package/dist/auth/index.d.ts +1 -0
- package/dist/auth/index.js +2 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/{context.util.js → context/context.js} +1 -1
- package/dist/context/context.js.map +1 -0
- package/dist/context/index.d.ts +1 -0
- package/dist/context/index.js +2 -0
- package/dist/context/index.js.map +1 -0
- package/dist/{controller.util.js → controller/controller.js} +1 -1
- package/dist/controller/controller.js.map +1 -0
- package/dist/controller/index.d.ts +1 -0
- package/dist/controller/index.js +2 -0
- package/dist/controller/index.js.map +1 -0
- package/dist/{conversion.util.js → conversion/conversion.js} +1 -1
- package/dist/conversion/conversion.js.map +1 -0
- package/dist/conversion/index.d.ts +1 -0
- package/dist/conversion/index.js +2 -0
- package/dist/conversion/index.js.map +1 -0
- package/dist/{db.util.d.ts → db/db.d.ts} +9 -5
- package/dist/{db.util.js → db/db.js} +40 -29
- package/dist/db/db.js.map +1 -0
- package/dist/db/index.d.ts +1 -0
- package/dist/db/index.js +2 -0
- package/dist/db/index.js.map +1 -0
- package/dist/index.d.ts +14 -13
- package/dist/index.js +14 -13
- package/dist/index.js.map +1 -1
- package/dist/logger/index.d.ts +1 -0
- package/dist/logger/index.js +2 -0
- package/dist/logger/index.js.map +1 -0
- package/dist/{logger.util.js → logger/logger.js} +16 -7
- package/dist/logger/logger.js.map +1 -0
- package/dist/mail/index.d.ts +1 -0
- package/dist/mail/index.js +2 -0
- package/dist/mail/index.js.map +1 -0
- package/dist/{mail.util.js → mail/mail.js} +1 -1
- package/dist/mail/mail.js.map +1 -0
- package/dist/middleware/index.d.ts +1 -0
- package/dist/middleware/index.js +2 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/{middleware.util.js → middleware/middleware.js} +1 -1
- package/dist/middleware/middleware.js.map +1 -0
- package/dist/model/index.d.ts +1 -0
- package/dist/model/index.js +2 -0
- package/dist/model/index.js.map +1 -0
- package/dist/{model.util.js → model/model.js} +1 -1
- package/dist/model/model.js.map +1 -0
- package/dist/permission/index.d.ts +1 -0
- package/dist/permission/index.js +2 -0
- package/dist/permission/index.js.map +1 -0
- package/dist/{permission.util.js → permission/permission.js} +1 -1
- package/dist/permission/permission.js.map +1 -0
- package/dist/registry/index.d.ts +1 -0
- package/dist/registry/index.js +2 -0
- package/dist/registry/index.js.map +1 -0
- package/dist/registry/registry.d.ts +28 -0
- package/dist/registry/registry.js +19 -0
- package/dist/registry/registry.js.map +1 -0
- package/dist/route/index.d.ts +1 -0
- package/dist/route/index.js +2 -0
- package/dist/route/index.js.map +1 -0
- package/dist/{route.util.js → route/route.js} +1 -1
- package/dist/route/route.js.map +1 -0
- package/dist/storage/index.d.ts +1 -0
- package/dist/storage/index.js +2 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/{storage.util.js → storage/storage.js} +2 -2
- package/dist/storage/storage.js.map +1 -0
- package/dist/validation/index.d.ts +1 -0
- package/dist/validation/index.js +2 -0
- package/dist/validation/index.js.map +1 -0
- package/dist/{validation.util.js → validation/validation.js} +1 -1
- package/dist/validation/validation.js.map +1 -0
- package/package.json +2 -2
- package/src/{auth.util.ts → auth/auth.ts} +255 -241
- package/src/auth/index.ts +1 -0
- package/src/{context.util.ts → context/context.ts} +17 -17
- package/src/context/index.ts +1 -0
- package/src/{controller.util.ts → controller/controller.ts} +236 -236
- package/src/controller/index.ts +1 -0
- package/src/{conversion.util.ts → conversion/conversion.ts} +64 -64
- package/src/conversion/index.ts +1 -0
- package/src/{db.util.ts → db/db.ts} +420 -405
- package/src/db/index.ts +1 -0
- package/src/index.ts +14 -13
- package/src/logger/index.ts +1 -0
- package/src/{logger.util.ts → logger/logger.ts} +176 -169
- package/src/mail/index.ts +1 -0
- package/src/{mail.util.ts → mail/mail.ts} +85 -85
- package/src/middleware/index.ts +1 -0
- package/src/{middleware.util.ts → middleware/middleware.ts} +288 -288
- package/src/model/index.ts +1 -0
- package/src/{model.util.ts → model/model.ts} +2210 -2210
- package/src/permission/index.ts +1 -0
- package/src/{permission.util.ts → permission/permission.ts} +136 -136
- package/src/registry/index.ts +1 -0
- package/src/registry/registry.ts +37 -0
- package/src/route/index.ts +1 -0
- package/src/{route.util.ts → route/route.ts} +11 -11
- package/src/storage/index.ts +1 -0
- package/src/{storage.util.ts → storage/storage.ts} +101 -101
- package/src/validation/index.ts +1 -0
- package/src/{validation.util.ts → validation/validation.ts} +338 -338
- package/tsconfig.json +1 -1
- package/bun.lock +0 -160
- package/dist/auth.util.js.map +0 -1
- package/dist/context.util.js.map +0 -1
- package/dist/controller.util.js.map +0 -1
- package/dist/conversion.util.js.map +0 -1
- package/dist/db.util.js.map +0 -1
- package/dist/logger.util.js.map +0 -1
- package/dist/mail.util.js.map +0 -1
- package/dist/middleware.util.js.map +0 -1
- package/dist/model.util.js.map +0 -1
- package/dist/permission.util.js.map +0 -1
- package/dist/route.util.js.map +0 -1
- package/dist/storage.util.js.map +0 -1
- package/dist/validation.util.js.map +0 -1
- /package/dist/{context.util.d.ts → context/context.d.ts} +0 -0
- /package/dist/{controller.util.d.ts → controller/controller.d.ts} +0 -0
- /package/dist/{conversion.util.d.ts → conversion/conversion.d.ts} +0 -0
- /package/dist/{logger.util.d.ts → logger/logger.d.ts} +0 -0
- /package/dist/{mail.util.d.ts → mail/mail.d.ts} +0 -0
- /package/dist/{middleware.util.d.ts → middleware/middleware.d.ts} +0 -0
- /package/dist/{model.util.d.ts → model/model.d.ts} +0 -0
- /package/dist/{permission.util.d.ts → permission/permission.d.ts} +0 -0
- /package/dist/{route.util.d.ts → route/route.d.ts} +0 -0
- /package/dist/{storage.util.d.ts → storage/storage.d.ts} +0 -0
- /package/dist/{validation.util.d.ts → validation/validation.d.ts} +0 -0
package/src/db/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./db";
|
package/src/index.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
export * from "./auth
|
|
2
|
-
export * from "./controller
|
|
3
|
-
export * from "./conversion
|
|
4
|
-
export * from "./context
|
|
5
|
-
export * from "./db
|
|
6
|
-
export * from "./middleware
|
|
7
|
-
export * from "./model
|
|
8
|
-
export * from "./permission
|
|
9
|
-
export * from "./route
|
|
10
|
-
export * from "./storage
|
|
11
|
-
export * from "./validation
|
|
12
|
-
export * from "./mail
|
|
13
|
-
export * from "./logger
|
|
1
|
+
export * from "./auth";
|
|
2
|
+
export * from "./controller";
|
|
3
|
+
export * from "./conversion";
|
|
4
|
+
export * from "./context";
|
|
5
|
+
export * from "./db";
|
|
6
|
+
export * from "./middleware";
|
|
7
|
+
export * from "./model";
|
|
8
|
+
export * from "./permission";
|
|
9
|
+
export * from "./route";
|
|
10
|
+
export * from "./storage";
|
|
11
|
+
export * from "./validation";
|
|
12
|
+
export * from "./mail";
|
|
13
|
+
export * from "./logger";
|
|
14
|
+
export * from "./registry";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./logger";
|
|
@@ -1,170 +1,177 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
console
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
const
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
const
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
//
|
|
112
|
-
//
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { registry } from '@utils/registry';
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
type LogType = "start" | "info" | "error" | "warning" | "cron" | "queue" | "queueError" | "cronError" | "socket" | "socketError";
|
|
8
|
+
|
|
9
|
+
export interface AccessLog {
|
|
10
|
+
method : string
|
|
11
|
+
path : string
|
|
12
|
+
status : number
|
|
13
|
+
latency : number
|
|
14
|
+
ip ?: string | null
|
|
15
|
+
agent ?: string | null
|
|
16
|
+
at ?: string
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface ErrorLog {
|
|
20
|
+
service ?: string
|
|
21
|
+
key ?: string
|
|
22
|
+
feature ?: string
|
|
23
|
+
error : string | null
|
|
24
|
+
reference ?: string | null
|
|
25
|
+
at ?: string
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
const colors: Record<LogType | "default", string> = {
|
|
32
|
+
default : "\x1b[0m", // default
|
|
33
|
+
start : "\x1b[32m", // green
|
|
34
|
+
info : "\x1b[36m", // cyan
|
|
35
|
+
error : "\x1b[31m", // red
|
|
36
|
+
warning : "\x1b[33m", // yellow
|
|
37
|
+
queue : "\x1b[34m", // blue
|
|
38
|
+
queueError : "\x1b[31m", // red
|
|
39
|
+
cron : "\x1b[35m", // magenta
|
|
40
|
+
cronError : "\x1b[31m", // red
|
|
41
|
+
socket : "\x1b[35m", // blue
|
|
42
|
+
socketError : "\x1b[31m", // red
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const prefixes: Record<LogType, string> = {
|
|
46
|
+
start : "START",
|
|
47
|
+
info : "INFO",
|
|
48
|
+
error : "ERROR",
|
|
49
|
+
warning : "WARNING",
|
|
50
|
+
cron : "CRON",
|
|
51
|
+
queue : "QUEUE",
|
|
52
|
+
socket : "SOCKET",
|
|
53
|
+
queueError : "QUEUE ERROR",
|
|
54
|
+
cronError : "CRON ERROR",
|
|
55
|
+
socketError : "SOCKET ERROR",
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
function log(type: LogType, msg: string) {
|
|
59
|
+
const color = colors[type];
|
|
60
|
+
const prefix = prefixes[type];
|
|
61
|
+
// eslint-disable-next-line no-console
|
|
62
|
+
console.log(`${color}[${prefix}]${colors.default}`, msg);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export const logger = {
|
|
66
|
+
start : (msg: string) => log("start", msg),
|
|
67
|
+
info : (msg: string) => log("info", msg),
|
|
68
|
+
warning : (msg: string) => log("warning", msg),
|
|
69
|
+
queue : (msg: string) => log("queue", msg),
|
|
70
|
+
cron : (msg: string) => log("cron", msg),
|
|
71
|
+
socket : (msg: string) => log("socket", msg),
|
|
72
|
+
|
|
73
|
+
access : (msg: AccessLog) => logAccess(msg),
|
|
74
|
+
|
|
75
|
+
error: (msg: string, payload?: ErrorLog) => {
|
|
76
|
+
log("error", msg)
|
|
77
|
+
payload && logError({...payload, service: payload.service || 'app'})
|
|
78
|
+
},
|
|
79
|
+
queueError: (msg: string, payload?: ErrorLog) => {
|
|
80
|
+
log("queueError", msg)
|
|
81
|
+
payload && logError({...payload, service: payload.service || 'queue'})
|
|
82
|
+
},
|
|
83
|
+
cronError: (msg: string, payload?: ErrorLog) => {
|
|
84
|
+
log("cronError", msg)
|
|
85
|
+
payload && logError({...payload, service: payload.service || 'cron'})
|
|
86
|
+
},
|
|
87
|
+
socketError: (msg: string, payload?: ErrorLog) => {
|
|
88
|
+
log("socketError", msg)
|
|
89
|
+
payload && logError({...payload, service: payload.service || 'socket'})
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
type DriverName = "file" | "da"
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
const ACCESS_LOG_DRIVER = process.env.ACCESS_LOG_DRIVER || "file"
|
|
101
|
+
const ACCESS_LOG_LOG_DIR = process.env.ACCESS_LOG_DIR || "storage/logs/access"
|
|
102
|
+
const ACCESS_LOG_QUEUE = process.env.ACCESS_LOG_QUEUE || "access-log"
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
const ERROR_LOG_DRIVER = process.env.ERROR_LOG_DRIVER || "file"
|
|
106
|
+
const ERROR_LOG_LOG_DIR = process.env.ERROR_LOG_DIR || "storage/logs/error"
|
|
107
|
+
const ERROR_LOG_QUEUE = process.env.ERROR_LOG_QUEUE_PREFIX || "error-log"
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
// =====================
|
|
112
|
+
// ## Access Log Drivers
|
|
113
|
+
// =====================
|
|
114
|
+
const filePath = () => {
|
|
115
|
+
const d = new Date().toISOString().slice(0, 10)
|
|
116
|
+
return path.resolve( ACCESS_LOG_LOG_DIR, `access-${d}.log`)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const handlers: Record<DriverName, (log: AccessLog) => Promise<void>> = {
|
|
120
|
+
file: async (log) => {
|
|
121
|
+
const dir = path.resolve(ACCESS_LOG_LOG_DIR);
|
|
122
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
123
|
+
|
|
124
|
+
fs.appendFile(filePath(), JSON.stringify(log) + "\n", () => {})
|
|
125
|
+
},
|
|
126
|
+
da: async (log) => {
|
|
127
|
+
const queue = registry.get('queue')
|
|
128
|
+
if (queue) {
|
|
129
|
+
try {
|
|
130
|
+
await queue.add(ACCESS_LOG_QUEUE, log)
|
|
131
|
+
} catch {}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const activeDrivers: DriverName[] = (ACCESS_LOG_DRIVER).split(",").map(v => v.trim()).filter((v): v is DriverName => v in handlers)
|
|
137
|
+
|
|
138
|
+
function logAccess(payload: AccessLog) {
|
|
139
|
+
for (const d of activeDrivers) {
|
|
140
|
+
handlers[d](payload)
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
// =====================
|
|
147
|
+
// ## Error Log Drivers
|
|
148
|
+
// =====================
|
|
149
|
+
const errorFilePath = () => {
|
|
150
|
+
const d = new Date().toISOString().slice(0, 10)
|
|
151
|
+
return path.resolve(ERROR_LOG_LOG_DIR, `error-${d}.log`)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const errorHandlers: Record<DriverName, (log: ErrorLog) => Promise<void>> = {
|
|
155
|
+
file: async (log) => {
|
|
156
|
+
const dir = path.resolve(ERROR_LOG_LOG_DIR);
|
|
157
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
158
|
+
|
|
159
|
+
fs.appendFile(errorFilePath(), JSON.stringify(log) + "\n", () => {});
|
|
160
|
+
},
|
|
161
|
+
da: async (log) => {
|
|
162
|
+
const queue = registry.get('queue')
|
|
163
|
+
if (queue) {
|
|
164
|
+
try {
|
|
165
|
+
await queue.add(ERROR_LOG_QUEUE, log)
|
|
166
|
+
} catch {}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const activeErrorDrivers: DriverName[] = ERROR_LOG_DRIVER.split(",").map(v => v.trim()).filter((v): v is DriverName => v in errorHandlers)
|
|
172
|
+
|
|
173
|
+
function logError(payload: ErrorLog) {
|
|
174
|
+
for (const d of activeErrorDrivers) {
|
|
175
|
+
errorHandlers[d](payload)
|
|
176
|
+
}
|
|
170
177
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./mail";
|
|
@@ -1,86 +1,86 @@
|
|
|
1
|
-
import { readFileSync } from "fs";
|
|
2
|
-
import { join } from "path";
|
|
3
|
-
import nodemailer, { SentMessageInfo } from "nodemailer";
|
|
4
|
-
import { logger } from "@utils";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
export interface SendMailOptions {
|
|
9
|
-
to : string;
|
|
10
|
-
subject : string;
|
|
11
|
-
content ?: string;
|
|
12
|
-
text ?: string;
|
|
13
|
-
attachments ?: {
|
|
14
|
-
filename : string;
|
|
15
|
-
path : string;
|
|
16
|
-
}[];
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
// =============================>
|
|
22
|
-
// ## Mail: Send mail
|
|
23
|
-
// =============================>
|
|
24
|
-
export async function sendMail(options: {
|
|
25
|
-
to : string;
|
|
26
|
-
subject : string;
|
|
27
|
-
text ?: string;
|
|
28
|
-
content ?: string;
|
|
29
|
-
attachments ?: { filename: string; path: string }[];
|
|
30
|
-
}) {
|
|
31
|
-
const transporter = nodemailer.createTransport({
|
|
32
|
-
host : process.env.MAIL_HOST,
|
|
33
|
-
port : Number(process.env.MAIL_PORT),
|
|
34
|
-
secure : Number(process.env.MAIL_PORT) === 465,
|
|
35
|
-
auth : {
|
|
36
|
-
user : process.env.MAIL_USERNAME,
|
|
37
|
-
pass : process.env.MAIL_PASSWORD,
|
|
38
|
-
},
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
const info = (await transporter.sendMail({
|
|
42
|
-
from : `${process.env.MAIL_FROM_NAME || process.env.APP_NAME} <${process.env.MAIL_FROM_ADDRESS || process.env.MAIL_USERNAME}>`,
|
|
43
|
-
to : options.to,
|
|
44
|
-
subject : options.subject,
|
|
45
|
-
text : options.text,
|
|
46
|
-
html : options.content,
|
|
47
|
-
attachments : options.attachments,
|
|
48
|
-
})) as SentMessageInfo;
|
|
49
|
-
|
|
50
|
-
logger.info(`Email sent successfully: ${info.messageId}`)
|
|
51
|
-
return info;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
// =============================>
|
|
57
|
-
// ## Mail: Render mail template
|
|
58
|
-
// =============================>
|
|
59
|
-
export function renderMailTemplate(template: string, options: Record<string, string>) {
|
|
60
|
-
const templateDir = join(import.meta.dir, "./../outputs/mails/templates");
|
|
61
|
-
|
|
62
|
-
const contentPath = join(templateDir, `${template}.mail.stub`);
|
|
63
|
-
let content = readFileSync(contentPath, "utf-8");
|
|
64
|
-
|
|
65
|
-
for (const [key, value] of Object.entries(options)) {
|
|
66
|
-
const regex = new RegExp(`{{\\s*${key}\\s*}}`, "g");
|
|
67
|
-
content = content.replace(regex, value);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
let layout = readFileSync(join(templateDir, "layout.mail.stub"), "utf-8");
|
|
71
|
-
|
|
72
|
-
const globalVars = {
|
|
73
|
-
...options,
|
|
74
|
-
date : "20-10-2025",
|
|
75
|
-
app_name : process.env.APP_NAME || "",
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
for (const [key, value] of Object.entries(globalVars)) {
|
|
79
|
-
const regex = new RegExp(`{{\\s*${key}\\s*}}`, "g");
|
|
80
|
-
layout = layout.replace(regex, value);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
layout = layout.replace("{{content}}", content);
|
|
84
|
-
|
|
85
|
-
return layout;
|
|
1
|
+
import { readFileSync } from "fs";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
import nodemailer, { SentMessageInfo } from "nodemailer";
|
|
4
|
+
import { logger } from "@utils";
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
export interface SendMailOptions {
|
|
9
|
+
to : string;
|
|
10
|
+
subject : string;
|
|
11
|
+
content ?: string;
|
|
12
|
+
text ?: string;
|
|
13
|
+
attachments ?: {
|
|
14
|
+
filename : string;
|
|
15
|
+
path : string;
|
|
16
|
+
}[];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
// =============================>
|
|
22
|
+
// ## Mail: Send mail
|
|
23
|
+
// =============================>
|
|
24
|
+
export async function sendMail(options: {
|
|
25
|
+
to : string;
|
|
26
|
+
subject : string;
|
|
27
|
+
text ?: string;
|
|
28
|
+
content ?: string;
|
|
29
|
+
attachments ?: { filename: string; path: string }[];
|
|
30
|
+
}) {
|
|
31
|
+
const transporter = nodemailer.createTransport({
|
|
32
|
+
host : process.env.MAIL_HOST,
|
|
33
|
+
port : Number(process.env.MAIL_PORT),
|
|
34
|
+
secure : Number(process.env.MAIL_PORT) === 465,
|
|
35
|
+
auth : {
|
|
36
|
+
user : process.env.MAIL_USERNAME,
|
|
37
|
+
pass : process.env.MAIL_PASSWORD,
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const info = (await transporter.sendMail({
|
|
42
|
+
from : `${process.env.MAIL_FROM_NAME || process.env.APP_NAME} <${process.env.MAIL_FROM_ADDRESS || process.env.MAIL_USERNAME}>`,
|
|
43
|
+
to : options.to,
|
|
44
|
+
subject : options.subject,
|
|
45
|
+
text : options.text,
|
|
46
|
+
html : options.content,
|
|
47
|
+
attachments : options.attachments,
|
|
48
|
+
})) as SentMessageInfo;
|
|
49
|
+
|
|
50
|
+
logger.info(`Email sent successfully: ${info.messageId}`)
|
|
51
|
+
return info;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
// =============================>
|
|
57
|
+
// ## Mail: Render mail template
|
|
58
|
+
// =============================>
|
|
59
|
+
export function renderMailTemplate(template: string, options: Record<string, string>) {
|
|
60
|
+
const templateDir = join(import.meta.dir, "./../outputs/mails/templates");
|
|
61
|
+
|
|
62
|
+
const contentPath = join(templateDir, `${template}.mail.stub`);
|
|
63
|
+
let content = readFileSync(contentPath, "utf-8");
|
|
64
|
+
|
|
65
|
+
for (const [key, value] of Object.entries(options)) {
|
|
66
|
+
const regex = new RegExp(`{{\\s*${key}\\s*}}`, "g");
|
|
67
|
+
content = content.replace(regex, value);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
let layout = readFileSync(join(templateDir, "layout.mail.stub"), "utf-8");
|
|
71
|
+
|
|
72
|
+
const globalVars = {
|
|
73
|
+
...options,
|
|
74
|
+
date : "20-10-2025",
|
|
75
|
+
app_name : process.env.APP_NAME || "",
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
for (const [key, value] of Object.entries(globalVars)) {
|
|
79
|
+
const regex = new RegExp(`{{\\s*${key}\\s*}}`, "g");
|
|
80
|
+
layout = layout.replace(regex, value);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
layout = layout.replace("{{content}}", content);
|
|
84
|
+
|
|
85
|
+
return layout;
|
|
86
86
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./middleware";
|