@bloomneo/appkit 1.2.9
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/LICENSE +21 -0
- package/README.md +902 -0
- package/bin/appkit.js +71 -0
- package/bin/commands/generate.js +1050 -0
- package/bin/templates/backend/README.md.template +39 -0
- package/bin/templates/backend/api.http.template +0 -0
- package/bin/templates/backend/docs/APPKIT_CLI.md +507 -0
- package/bin/templates/backend/docs/APPKIT_COMMENTS_GUIDELINES.md +61 -0
- package/bin/templates/backend/docs/APPKIT_LLM_GUIDE.md +2539 -0
- package/bin/templates/backend/package.json.template +34 -0
- package/bin/templates/backend/src/api/features/welcome/welcome.http.template +29 -0
- package/bin/templates/backend/src/api/features/welcome/welcome.route.ts.template +36 -0
- package/bin/templates/backend/src/api/features/welcome/welcome.service.ts.template +88 -0
- package/bin/templates/backend/src/api/features/welcome/welcome.types.ts.template +18 -0
- package/bin/templates/backend/src/api/lib/api-router.ts.template +84 -0
- package/bin/templates/backend/src/api/server.ts.template +188 -0
- package/bin/templates/backend/tsconfig.api.json.template +24 -0
- package/bin/templates/backend/tsconfig.json.template +40 -0
- package/bin/templates/feature/feature.http.template +63 -0
- package/bin/templates/feature/feature.route.ts.template +36 -0
- package/bin/templates/feature/feature.service.ts.template +81 -0
- package/bin/templates/feature/feature.types.ts.template +23 -0
- package/bin/templates/feature-db/feature.http.template +63 -0
- package/bin/templates/feature-db/feature.model.ts.template +74 -0
- package/bin/templates/feature-db/feature.route.ts.template +58 -0
- package/bin/templates/feature-db/feature.service.ts.template +231 -0
- package/bin/templates/feature-db/feature.types.ts.template +25 -0
- package/bin/templates/feature-db/schema-addition.prisma.template +9 -0
- package/bin/templates/feature-db/seeding/README.md.template +57 -0
- package/bin/templates/feature-db/seeding/feature.seed.js.template +67 -0
- package/bin/templates/feature-user/schema-addition.prisma.template +19 -0
- package/bin/templates/feature-user/user.http.template +157 -0
- package/bin/templates/feature-user/user.model.ts.template +244 -0
- package/bin/templates/feature-user/user.route.ts.template +379 -0
- package/bin/templates/feature-user/user.seed.js.template +182 -0
- package/bin/templates/feature-user/user.service.ts.template +426 -0
- package/bin/templates/feature-user/user.types.ts.template +127 -0
- package/dist/auth/auth.d.ts +182 -0
- package/dist/auth/auth.d.ts.map +1 -0
- package/dist/auth/auth.js +477 -0
- package/dist/auth/auth.js.map +1 -0
- package/dist/auth/defaults.d.ts +104 -0
- package/dist/auth/defaults.d.ts.map +1 -0
- package/dist/auth/defaults.js +374 -0
- package/dist/auth/defaults.js.map +1 -0
- package/dist/auth/index.d.ts +70 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +94 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/cache/cache.d.ts +118 -0
- package/dist/cache/cache.d.ts.map +1 -0
- package/dist/cache/cache.js +249 -0
- package/dist/cache/cache.js.map +1 -0
- package/dist/cache/defaults.d.ts +63 -0
- package/dist/cache/defaults.d.ts.map +1 -0
- package/dist/cache/defaults.js +193 -0
- package/dist/cache/defaults.js.map +1 -0
- package/dist/cache/index.d.ts +101 -0
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/index.js +203 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/cache/strategies/memory.d.ts +138 -0
- package/dist/cache/strategies/memory.d.ts.map +1 -0
- package/dist/cache/strategies/memory.js +348 -0
- package/dist/cache/strategies/memory.js.map +1 -0
- package/dist/cache/strategies/redis.d.ts +105 -0
- package/dist/cache/strategies/redis.d.ts.map +1 -0
- package/dist/cache/strategies/redis.js +318 -0
- package/dist/cache/strategies/redis.js.map +1 -0
- package/dist/config/config.d.ts +62 -0
- package/dist/config/config.d.ts.map +1 -0
- package/dist/config/config.js +107 -0
- package/dist/config/config.js.map +1 -0
- package/dist/config/defaults.d.ts +44 -0
- package/dist/config/defaults.d.ts.map +1 -0
- package/dist/config/defaults.js +217 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/config/index.d.ts +105 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +163 -0
- package/dist/config/index.js.map +1 -0
- package/dist/database/adapters/mongoose.d.ts +106 -0
- package/dist/database/adapters/mongoose.d.ts.map +1 -0
- package/dist/database/adapters/mongoose.js +480 -0
- package/dist/database/adapters/mongoose.js.map +1 -0
- package/dist/database/adapters/prisma.d.ts +106 -0
- package/dist/database/adapters/prisma.d.ts.map +1 -0
- package/dist/database/adapters/prisma.js +494 -0
- package/dist/database/adapters/prisma.js.map +1 -0
- package/dist/database/defaults.d.ts +87 -0
- package/dist/database/defaults.d.ts.map +1 -0
- package/dist/database/defaults.js +271 -0
- package/dist/database/defaults.js.map +1 -0
- package/dist/database/index.d.ts +137 -0
- package/dist/database/index.d.ts.map +1 -0
- package/dist/database/index.js +490 -0
- package/dist/database/index.js.map +1 -0
- package/dist/email/defaults.d.ts +100 -0
- package/dist/email/defaults.d.ts.map +1 -0
- package/dist/email/defaults.js +400 -0
- package/dist/email/defaults.js.map +1 -0
- package/dist/email/email.d.ts +139 -0
- package/dist/email/email.d.ts.map +1 -0
- package/dist/email/email.js +316 -0
- package/dist/email/email.js.map +1 -0
- package/dist/email/index.d.ts +176 -0
- package/dist/email/index.d.ts.map +1 -0
- package/dist/email/index.js +251 -0
- package/dist/email/index.js.map +1 -0
- package/dist/email/strategies/console.d.ts +90 -0
- package/dist/email/strategies/console.d.ts.map +1 -0
- package/dist/email/strategies/console.js +268 -0
- package/dist/email/strategies/console.js.map +1 -0
- package/dist/email/strategies/resend.d.ts +84 -0
- package/dist/email/strategies/resend.d.ts.map +1 -0
- package/dist/email/strategies/resend.js +266 -0
- package/dist/email/strategies/resend.js.map +1 -0
- package/dist/email/strategies/smtp.d.ts +77 -0
- package/dist/email/strategies/smtp.d.ts.map +1 -0
- package/dist/email/strategies/smtp.js +286 -0
- package/dist/email/strategies/smtp.js.map +1 -0
- package/dist/error/defaults.d.ts +40 -0
- package/dist/error/defaults.d.ts.map +1 -0
- package/dist/error/defaults.js +75 -0
- package/dist/error/defaults.js.map +1 -0
- package/dist/error/error.d.ts +140 -0
- package/dist/error/error.d.ts.map +1 -0
- package/dist/error/error.js +200 -0
- package/dist/error/error.js.map +1 -0
- package/dist/error/index.d.ts +145 -0
- package/dist/error/index.d.ts.map +1 -0
- package/dist/error/index.js +145 -0
- package/dist/error/index.js.map +1 -0
- package/dist/event/defaults.d.ts +111 -0
- package/dist/event/defaults.d.ts.map +1 -0
- package/dist/event/defaults.js +378 -0
- package/dist/event/defaults.js.map +1 -0
- package/dist/event/event.d.ts +171 -0
- package/dist/event/event.d.ts.map +1 -0
- package/dist/event/event.js +391 -0
- package/dist/event/event.js.map +1 -0
- package/dist/event/index.d.ts +173 -0
- package/dist/event/index.d.ts.map +1 -0
- package/dist/event/index.js +302 -0
- package/dist/event/index.js.map +1 -0
- package/dist/event/strategies/memory.d.ts +122 -0
- package/dist/event/strategies/memory.d.ts.map +1 -0
- package/dist/event/strategies/memory.js +331 -0
- package/dist/event/strategies/memory.js.map +1 -0
- package/dist/event/strategies/redis.d.ts +115 -0
- package/dist/event/strategies/redis.d.ts.map +1 -0
- package/dist/event/strategies/redis.js +434 -0
- package/dist/event/strategies/redis.js.map +1 -0
- package/dist/index.d.ts +58 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +72 -0
- package/dist/index.js.map +1 -0
- package/dist/logger/defaults.d.ts +67 -0
- package/dist/logger/defaults.d.ts.map +1 -0
- package/dist/logger/defaults.js +213 -0
- package/dist/logger/defaults.js.map +1 -0
- package/dist/logger/index.d.ts +84 -0
- package/dist/logger/index.d.ts.map +1 -0
- package/dist/logger/index.js +101 -0
- package/dist/logger/index.js.map +1 -0
- package/dist/logger/logger.d.ts +165 -0
- package/dist/logger/logger.d.ts.map +1 -0
- package/dist/logger/logger.js +843 -0
- package/dist/logger/logger.js.map +1 -0
- package/dist/logger/transports/console.d.ts +102 -0
- package/dist/logger/transports/console.d.ts.map +1 -0
- package/dist/logger/transports/console.js +276 -0
- package/dist/logger/transports/console.js.map +1 -0
- package/dist/logger/transports/database.d.ts +153 -0
- package/dist/logger/transports/database.d.ts.map +1 -0
- package/dist/logger/transports/database.js +539 -0
- package/dist/logger/transports/database.js.map +1 -0
- package/dist/logger/transports/file.d.ts +146 -0
- package/dist/logger/transports/file.d.ts.map +1 -0
- package/dist/logger/transports/file.js +464 -0
- package/dist/logger/transports/file.js.map +1 -0
- package/dist/logger/transports/http.d.ts +128 -0
- package/dist/logger/transports/http.d.ts.map +1 -0
- package/dist/logger/transports/http.js +401 -0
- package/dist/logger/transports/http.js.map +1 -0
- package/dist/logger/transports/webhook.d.ts +152 -0
- package/dist/logger/transports/webhook.d.ts.map +1 -0
- package/dist/logger/transports/webhook.js +485 -0
- package/dist/logger/transports/webhook.js.map +1 -0
- package/dist/queue/defaults.d.ts +66 -0
- package/dist/queue/defaults.d.ts.map +1 -0
- package/dist/queue/defaults.js +205 -0
- package/dist/queue/defaults.js.map +1 -0
- package/dist/queue/index.d.ts +124 -0
- package/dist/queue/index.d.ts.map +1 -0
- package/dist/queue/index.js +116 -0
- package/dist/queue/index.js.map +1 -0
- package/dist/queue/queue.d.ts +156 -0
- package/dist/queue/queue.d.ts.map +1 -0
- package/dist/queue/queue.js +387 -0
- package/dist/queue/queue.js.map +1 -0
- package/dist/queue/transports/database.d.ts +165 -0
- package/dist/queue/transports/database.d.ts.map +1 -0
- package/dist/queue/transports/database.js +595 -0
- package/dist/queue/transports/database.js.map +1 -0
- package/dist/queue/transports/memory.d.ts +143 -0
- package/dist/queue/transports/memory.d.ts.map +1 -0
- package/dist/queue/transports/memory.js +415 -0
- package/dist/queue/transports/memory.js.map +1 -0
- package/dist/queue/transports/redis.d.ts +203 -0
- package/dist/queue/transports/redis.d.ts.map +1 -0
- package/dist/queue/transports/redis.js +744 -0
- package/dist/queue/transports/redis.js.map +1 -0
- package/dist/security/defaults.d.ts +64 -0
- package/dist/security/defaults.d.ts.map +1 -0
- package/dist/security/defaults.js +159 -0
- package/dist/security/defaults.js.map +1 -0
- package/dist/security/index.d.ts +110 -0
- package/dist/security/index.d.ts.map +1 -0
- package/dist/security/index.js +160 -0
- package/dist/security/index.js.map +1 -0
- package/dist/security/security.d.ts +138 -0
- package/dist/security/security.d.ts.map +1 -0
- package/dist/security/security.js +419 -0
- package/dist/security/security.js.map +1 -0
- package/dist/storage/defaults.d.ts +79 -0
- package/dist/storage/defaults.d.ts.map +1 -0
- package/dist/storage/defaults.js +358 -0
- package/dist/storage/defaults.js.map +1 -0
- package/dist/storage/index.d.ts +153 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +242 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/storage.d.ts +151 -0
- package/dist/storage/storage.d.ts.map +1 -0
- package/dist/storage/storage.js +439 -0
- package/dist/storage/storage.js.map +1 -0
- package/dist/storage/strategies/local.d.ts +117 -0
- package/dist/storage/strategies/local.d.ts.map +1 -0
- package/dist/storage/strategies/local.js +368 -0
- package/dist/storage/strategies/local.js.map +1 -0
- package/dist/storage/strategies/r2.d.ts +130 -0
- package/dist/storage/strategies/r2.d.ts.map +1 -0
- package/dist/storage/strategies/r2.js +470 -0
- package/dist/storage/strategies/r2.js.map +1 -0
- package/dist/storage/strategies/s3.d.ts +121 -0
- package/dist/storage/strategies/s3.d.ts.map +1 -0
- package/dist/storage/strategies/s3.js +461 -0
- package/dist/storage/strategies/s3.js.map +1 -0
- package/dist/util/defaults.d.ts +77 -0
- package/dist/util/defaults.d.ts.map +1 -0
- package/dist/util/defaults.js +193 -0
- package/dist/util/defaults.js.map +1 -0
- package/dist/util/index.d.ts +97 -0
- package/dist/util/index.d.ts.map +1 -0
- package/dist/util/index.js +165 -0
- package/dist/util/index.js.map +1 -0
- package/dist/util/util.d.ts +145 -0
- package/dist/util/util.d.ts.map +1 -0
- package/dist/util/util.js +481 -0
- package/dist/util/util.js.map +1 -0
- package/package.json +234 -0
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SMTP email strategy with nodemailer and connection pooling
|
|
3
|
+
* @module @bloomneo/appkit/email
|
|
4
|
+
* @file src/email/strategies/smtp.ts
|
|
5
|
+
*
|
|
6
|
+
* @llm-rule WHEN: App has SMTP_HOST environment variable for universal email sending
|
|
7
|
+
* @llm-rule AVOID: Manual SMTP setup - this handles connection pooling, authentication, and reliability
|
|
8
|
+
* @llm-rule NOTE: Universal email strategy that works with any SMTP server (Gmail, Outlook, etc.)
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* SMTP email strategy with connection pooling and reliability features
|
|
12
|
+
*/
|
|
13
|
+
export class SmtpStrategy {
|
|
14
|
+
config;
|
|
15
|
+
transporter = null;
|
|
16
|
+
connected = false;
|
|
17
|
+
/**
|
|
18
|
+
* Creates SMTP strategy with direct environment access (like auth pattern)
|
|
19
|
+
* @llm-rule WHEN: Email initialization with SMTP_HOST detected
|
|
20
|
+
* @llm-rule AVOID: Manual SMTP configuration - environment detection handles this
|
|
21
|
+
*/
|
|
22
|
+
constructor(config) {
|
|
23
|
+
this.config = config;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Sends email via SMTP with automatic connection management
|
|
27
|
+
* @llm-rule WHEN: Sending emails through SMTP servers
|
|
28
|
+
* @llm-rule AVOID: Manual SMTP calls - this handles all connection complexity
|
|
29
|
+
* @llm-rule NOTE: Includes connection pooling, authentication, and error handling
|
|
30
|
+
*/
|
|
31
|
+
async send(data) {
|
|
32
|
+
try {
|
|
33
|
+
// Ensure transporter is connected
|
|
34
|
+
await this.ensureConnected();
|
|
35
|
+
// Convert to nodemailer format
|
|
36
|
+
const mailOptions = this.convertToSmtpFormat(data);
|
|
37
|
+
// Send via SMTP
|
|
38
|
+
const result = await this.transporter.sendMail(mailOptions);
|
|
39
|
+
return {
|
|
40
|
+
success: true,
|
|
41
|
+
messageId: result.messageId,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
const errorMessage = this.parseSmtpError(error);
|
|
46
|
+
if (this.config.environment.isDevelopment) {
|
|
47
|
+
console.error(`[AppKit] SMTP error:`, errorMessage);
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
success: false,
|
|
51
|
+
error: errorMessage,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Disconnects SMTP strategy gracefully
|
|
57
|
+
* @llm-rule WHEN: App shutdown or email cleanup
|
|
58
|
+
* @llm-rule AVOID: Abrupt disconnection - graceful shutdown prevents connection issues
|
|
59
|
+
*/
|
|
60
|
+
async disconnect() {
|
|
61
|
+
if (!this.connected || !this.transporter)
|
|
62
|
+
return;
|
|
63
|
+
try {
|
|
64
|
+
await this.transporter.close();
|
|
65
|
+
this.connected = false;
|
|
66
|
+
this.transporter = null;
|
|
67
|
+
if (this.config.environment.isDevelopment) {
|
|
68
|
+
console.log(`👋 [AppKit] SMTP disconnected`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
console.error(`⚠️ [AppKit] SMTP disconnect error:`, error.message);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Private helper methods
|
|
76
|
+
/**
|
|
77
|
+
* Ensures SMTP transporter is connected
|
|
78
|
+
*/
|
|
79
|
+
async ensureConnected() {
|
|
80
|
+
if (this.connected && this.transporter)
|
|
81
|
+
return;
|
|
82
|
+
try {
|
|
83
|
+
// Dynamic import for nodemailer
|
|
84
|
+
const nodemailer = await import('nodemailer');
|
|
85
|
+
const smtpConfig = this.config.smtp;
|
|
86
|
+
// Create transporter with connection pooling
|
|
87
|
+
this.transporter = nodemailer.createTransport({
|
|
88
|
+
host: smtpConfig.host,
|
|
89
|
+
port: smtpConfig.port,
|
|
90
|
+
secure: smtpConfig.secure,
|
|
91
|
+
auth: smtpConfig.auth.user && smtpConfig.auth.pass ? {
|
|
92
|
+
user: smtpConfig.auth.user,
|
|
93
|
+
pass: smtpConfig.auth.pass,
|
|
94
|
+
} : undefined,
|
|
95
|
+
pool: smtpConfig.pool,
|
|
96
|
+
maxConnections: 5,
|
|
97
|
+
maxMessages: 100,
|
|
98
|
+
rateDelta: 1000,
|
|
99
|
+
rateLimit: 10,
|
|
100
|
+
connectionTimeout: smtpConfig.timeout,
|
|
101
|
+
socketTimeout: smtpConfig.timeout,
|
|
102
|
+
// Security options
|
|
103
|
+
tls: {
|
|
104
|
+
rejectUnauthorized: this.config.environment.isProduction,
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
// Verify connection
|
|
108
|
+
await this.transporter.verify();
|
|
109
|
+
this.connected = true;
|
|
110
|
+
if (this.config.environment.isDevelopment) {
|
|
111
|
+
console.log(`✅ [AppKit] SMTP connected to ${smtpConfig.host}:${smtpConfig.port}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
this.connected = false;
|
|
116
|
+
this.transporter = null;
|
|
117
|
+
throw new Error(`SMTP connection failed: ${error.message}`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Converts EmailData to nodemailer format
|
|
122
|
+
*/
|
|
123
|
+
convertToSmtpFormat(data) {
|
|
124
|
+
const mailOptions = {
|
|
125
|
+
from: this.formatEmailAddress(data.from),
|
|
126
|
+
to: this.formatEmailAddresses(data.to),
|
|
127
|
+
subject: data.subject,
|
|
128
|
+
};
|
|
129
|
+
// Add content
|
|
130
|
+
if (data.html) {
|
|
131
|
+
mailOptions.html = data.html;
|
|
132
|
+
}
|
|
133
|
+
if (data.text) {
|
|
134
|
+
mailOptions.text = data.text;
|
|
135
|
+
}
|
|
136
|
+
// Add optional fields
|
|
137
|
+
if (data.replyTo) {
|
|
138
|
+
mailOptions.replyTo = this.formatEmailAddress(data.replyTo);
|
|
139
|
+
}
|
|
140
|
+
if (data.cc) {
|
|
141
|
+
mailOptions.cc = this.formatEmailAddresses(data.cc);
|
|
142
|
+
}
|
|
143
|
+
if (data.bcc) {
|
|
144
|
+
mailOptions.bcc = this.formatEmailAddresses(data.bcc);
|
|
145
|
+
}
|
|
146
|
+
// Add attachments
|
|
147
|
+
if (data.attachments && data.attachments.length > 0) {
|
|
148
|
+
mailOptions.attachments = this.formatAttachments(data.attachments);
|
|
149
|
+
}
|
|
150
|
+
return mailOptions;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Formats single email address for nodemailer
|
|
154
|
+
*/
|
|
155
|
+
formatEmailAddress(address) {
|
|
156
|
+
if (typeof address === 'string') {
|
|
157
|
+
return address;
|
|
158
|
+
}
|
|
159
|
+
if (address.name) {
|
|
160
|
+
return `"${address.name}" <${address.email}>`;
|
|
161
|
+
}
|
|
162
|
+
return address.email;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Formats multiple email addresses for nodemailer
|
|
166
|
+
*/
|
|
167
|
+
formatEmailAddresses(addresses) {
|
|
168
|
+
const addressArray = Array.isArray(addresses) ? addresses : [addresses];
|
|
169
|
+
return addressArray.map(addr => this.formatEmailAddress(addr)).join(', ');
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Formats attachments for nodemailer
|
|
173
|
+
*/
|
|
174
|
+
formatAttachments(attachments) {
|
|
175
|
+
return attachments.map(attachment => ({
|
|
176
|
+
filename: attachment.filename,
|
|
177
|
+
content: attachment.content,
|
|
178
|
+
contentType: attachment.contentType || this.guessContentType(attachment.filename),
|
|
179
|
+
}));
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Guesses content type from filename
|
|
183
|
+
*/
|
|
184
|
+
guessContentType(filename) {
|
|
185
|
+
const ext = filename.split('.').pop()?.toLowerCase();
|
|
186
|
+
const mimeTypes = {
|
|
187
|
+
pdf: 'application/pdf',
|
|
188
|
+
doc: 'application/msword',
|
|
189
|
+
docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
190
|
+
xls: 'application/vnd.ms-excel',
|
|
191
|
+
xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
192
|
+
png: 'image/png',
|
|
193
|
+
jpg: 'image/jpeg',
|
|
194
|
+
jpeg: 'image/jpeg',
|
|
195
|
+
gif: 'image/gif',
|
|
196
|
+
txt: 'text/plain',
|
|
197
|
+
html: 'text/html',
|
|
198
|
+
css: 'text/css',
|
|
199
|
+
js: 'application/javascript',
|
|
200
|
+
json: 'application/json',
|
|
201
|
+
zip: 'application/zip',
|
|
202
|
+
};
|
|
203
|
+
return mimeTypes[ext || ''] || 'application/octet-stream';
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Parses SMTP errors into user-friendly messages
|
|
207
|
+
*/
|
|
208
|
+
parseSmtpError(error) {
|
|
209
|
+
if (error.message) {
|
|
210
|
+
const message = error.message.toLowerCase();
|
|
211
|
+
// Authentication errors
|
|
212
|
+
if (message.includes('authentication') || message.includes('invalid credentials') ||
|
|
213
|
+
message.includes('username') || message.includes('password')) {
|
|
214
|
+
return 'SMTP authentication failed. Check SMTP_USER and SMTP_PASS environment variables.';
|
|
215
|
+
}
|
|
216
|
+
// Connection errors
|
|
217
|
+
if (message.includes('connection') || message.includes('connect') ||
|
|
218
|
+
message.includes('econnrefused') || message.includes('timeout')) {
|
|
219
|
+
return 'SMTP connection failed. Check SMTP_HOST and SMTP_PORT environment variables.';
|
|
220
|
+
}
|
|
221
|
+
// TLS/SSL errors
|
|
222
|
+
if (message.includes('tls') || message.includes('ssl') || message.includes('secure')) {
|
|
223
|
+
return 'SMTP TLS/SSL error. Check SMTP_SECURE environment variable or server settings.';
|
|
224
|
+
}
|
|
225
|
+
// Rate limiting
|
|
226
|
+
if (message.includes('rate') || message.includes('limit') || message.includes('quota')) {
|
|
227
|
+
return 'SMTP rate limit exceeded. Please try again later.';
|
|
228
|
+
}
|
|
229
|
+
// Recipient errors
|
|
230
|
+
if (message.includes('recipient') || message.includes('address') ||
|
|
231
|
+
message.includes('mailbox') || message.includes('does not exist')) {
|
|
232
|
+
return 'Invalid recipient email address or mailbox does not exist.';
|
|
233
|
+
}
|
|
234
|
+
// Sender errors
|
|
235
|
+
if (message.includes('sender') || message.includes('from') ||
|
|
236
|
+
message.includes('not authorized') || message.includes('relay')) {
|
|
237
|
+
return 'SMTP sender not authorized. Check FROM address and server relay settings.';
|
|
238
|
+
}
|
|
239
|
+
// Message size errors
|
|
240
|
+
if (message.includes('size') || message.includes('too large') || message.includes('exceeded')) {
|
|
241
|
+
return 'Email message too large. Reduce attachment size or content length.';
|
|
242
|
+
}
|
|
243
|
+
// DNS errors
|
|
244
|
+
if (message.includes('dns') || message.includes('hostname') || message.includes('resolve')) {
|
|
245
|
+
return 'DNS resolution failed. Check SMTP_HOST value.';
|
|
246
|
+
}
|
|
247
|
+
// Port errors
|
|
248
|
+
if (message.includes('port') || message.includes('refused') || message.includes('unreachable')) {
|
|
249
|
+
return 'SMTP port connection failed. Check SMTP_PORT value and firewall settings.';
|
|
250
|
+
}
|
|
251
|
+
return error.message;
|
|
252
|
+
}
|
|
253
|
+
// Check for specific error codes
|
|
254
|
+
if (error.code) {
|
|
255
|
+
switch (error.code) {
|
|
256
|
+
case 'ECONNREFUSED':
|
|
257
|
+
return 'SMTP connection refused. Check SMTP_HOST and SMTP_PORT.';
|
|
258
|
+
case 'ENOTFOUND':
|
|
259
|
+
return 'SMTP host not found. Check SMTP_HOST value.';
|
|
260
|
+
case 'ETIMEDOUT':
|
|
261
|
+
return 'SMTP connection timeout. Check network connectivity.';
|
|
262
|
+
case 'ECONNRESET':
|
|
263
|
+
return 'SMTP connection reset. Server may be overloaded.';
|
|
264
|
+
case 'ESOCKET':
|
|
265
|
+
return 'SMTP socket error. Check network settings.';
|
|
266
|
+
default:
|
|
267
|
+
return `SMTP error: ${error.code}`;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return 'Unknown SMTP error occurred';
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Gets SMTP connection info for debugging
|
|
274
|
+
*/
|
|
275
|
+
getConnectionInfo() {
|
|
276
|
+
const smtpConfig = this.config.smtp;
|
|
277
|
+
return {
|
|
278
|
+
host: smtpConfig.host,
|
|
279
|
+
port: smtpConfig.port,
|
|
280
|
+
secure: smtpConfig.secure,
|
|
281
|
+
authenticated: !!(smtpConfig.auth.user && smtpConfig.auth.pass),
|
|
282
|
+
connected: this.connected,
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
//# sourceMappingURL=smtp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"smtp.js","sourceRoot":"","sources":["../../../src/email/strategies/smtp.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Smart defaults and environment validation for error handling
|
|
3
|
+
* @module @bloomneo/appkit/error
|
|
4
|
+
* @file src/error/defaults.ts
|
|
5
|
+
*
|
|
6
|
+
* @llm-rule WHEN: App startup - need to configure error handling behavior and messages
|
|
7
|
+
* @llm-rule AVOID: Calling multiple times - expensive environment parsing, use lazy loading in get()
|
|
8
|
+
* @llm-rule NOTE: Called once at startup, cached globally for performance
|
|
9
|
+
*/
|
|
10
|
+
export interface ErrorMessages {
|
|
11
|
+
badRequest: string;
|
|
12
|
+
unauthorized: string;
|
|
13
|
+
forbidden: string;
|
|
14
|
+
notFound: string;
|
|
15
|
+
conflict: string;
|
|
16
|
+
serverError: string;
|
|
17
|
+
}
|
|
18
|
+
export interface MiddlewareConfig {
|
|
19
|
+
showStack: boolean;
|
|
20
|
+
logErrors: boolean;
|
|
21
|
+
}
|
|
22
|
+
export interface EnvironmentConfig {
|
|
23
|
+
isDevelopment: boolean;
|
|
24
|
+
isProduction: boolean;
|
|
25
|
+
isTest: boolean;
|
|
26
|
+
nodeEnv: string;
|
|
27
|
+
}
|
|
28
|
+
export interface ErrorConfig {
|
|
29
|
+
messages: ErrorMessages;
|
|
30
|
+
middleware: MiddlewareConfig;
|
|
31
|
+
environment: EnvironmentConfig;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Gets smart defaults using VOILA_ERROR_* environment variables
|
|
35
|
+
* @llm-rule WHEN: App startup to get production-ready error configuration
|
|
36
|
+
* @llm-rule AVOID: Calling repeatedly - expensive validation, cache the result
|
|
37
|
+
* @llm-rule NOTE: Automatically configures dev vs production error behavior
|
|
38
|
+
*/
|
|
39
|
+
export declare function getSmartDefaults(): ErrorConfig;
|
|
40
|
+
//# sourceMappingURL=defaults.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../src/error/defaults.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,aAAa,EAAE,OAAO,CAAC;IACvB,YAAY,EAAE,OAAO,CAAC;IACtB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,aAAa,CAAC;IACxB,UAAU,EAAE,gBAAgB,CAAC;IAC7B,WAAW,EAAE,iBAAiB,CAAC;CAChC;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,IAAI,WAAW,CAiC9C"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Smart defaults and environment validation for error handling
|
|
3
|
+
* @module @bloomneo/appkit/error
|
|
4
|
+
* @file src/error/defaults.ts
|
|
5
|
+
*
|
|
6
|
+
* @llm-rule WHEN: App startup - need to configure error handling behavior and messages
|
|
7
|
+
* @llm-rule AVOID: Calling multiple times - expensive environment parsing, use lazy loading in get()
|
|
8
|
+
* @llm-rule NOTE: Called once at startup, cached globally for performance
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Gets smart defaults using VOILA_ERROR_* environment variables
|
|
12
|
+
* @llm-rule WHEN: App startup to get production-ready error configuration
|
|
13
|
+
* @llm-rule AVOID: Calling repeatedly - expensive validation, cache the result
|
|
14
|
+
* @llm-rule NOTE: Automatically configures dev vs production error behavior
|
|
15
|
+
*/
|
|
16
|
+
export function getSmartDefaults() {
|
|
17
|
+
validateEnvironment();
|
|
18
|
+
const nodeEnv = process.env.NODE_ENV || 'development';
|
|
19
|
+
const isDevelopment = nodeEnv === 'development';
|
|
20
|
+
const isProduction = nodeEnv === 'production';
|
|
21
|
+
const isTest = nodeEnv === 'test';
|
|
22
|
+
return {
|
|
23
|
+
// Error message defaults with environment awareness
|
|
24
|
+
messages: {
|
|
25
|
+
badRequest: 'Bad Request',
|
|
26
|
+
unauthorized: process.env.VOILA_AUTH_MESSAGE || 'Authentication required',
|
|
27
|
+
forbidden: 'Access denied',
|
|
28
|
+
notFound: 'Not found',
|
|
29
|
+
conflict: 'Conflict',
|
|
30
|
+
serverError: isDevelopment ? 'Internal server error' : 'Server error',
|
|
31
|
+
},
|
|
32
|
+
// Error handling behavior with smart defaults
|
|
33
|
+
middleware: {
|
|
34
|
+
showStack: process.env.VOILA_ERROR_STACK === 'true' || isDevelopment,
|
|
35
|
+
logErrors: process.env.VOILA_ERROR_LOG !== 'false',
|
|
36
|
+
},
|
|
37
|
+
// Environment information
|
|
38
|
+
environment: {
|
|
39
|
+
isDevelopment,
|
|
40
|
+
isProduction,
|
|
41
|
+
isTest,
|
|
42
|
+
nodeEnv,
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Validates environment variables for error configuration
|
|
48
|
+
* @llm-rule WHEN: App startup to ensure proper error environment configuration
|
|
49
|
+
* @llm-rule AVOID: Skipping validation - improper config causes silent failures
|
|
50
|
+
* @llm-rule NOTE: Validates essential boolean environment variables and NODE_ENV only
|
|
51
|
+
*/
|
|
52
|
+
function validateEnvironment() {
|
|
53
|
+
// Validate VOILA_ERROR_STACK (essential for security)
|
|
54
|
+
const errorStack = process.env.VOILA_ERROR_STACK;
|
|
55
|
+
if (errorStack && !['true', 'false'].includes(errorStack.toLowerCase())) {
|
|
56
|
+
throw new Error(`Invalid VOILA_ERROR_STACK: "${errorStack}". Must be "true" or "false"`);
|
|
57
|
+
}
|
|
58
|
+
// Validate VOILA_ERROR_LOG (essential for debugging)
|
|
59
|
+
const errorLog = process.env.VOILA_ERROR_LOG;
|
|
60
|
+
if (errorLog && !['true', 'false'].includes(errorLog.toLowerCase())) {
|
|
61
|
+
throw new Error(`Invalid VOILA_ERROR_LOG: "${errorLog}". Must be "true" or "false"`);
|
|
62
|
+
}
|
|
63
|
+
// Validate NODE_ENV (essential for environment detection)
|
|
64
|
+
const nodeEnv = process.env.NODE_ENV;
|
|
65
|
+
if (nodeEnv && !['development', 'production', 'test', 'staging'].includes(nodeEnv)) {
|
|
66
|
+
console.warn(`[VoilaJSX AppKit] Unusual NODE_ENV: "${nodeEnv}". ` +
|
|
67
|
+
`Expected: development, production, test, or staging`);
|
|
68
|
+
}
|
|
69
|
+
// Essential production safety check
|
|
70
|
+
if (nodeEnv === 'production' && process.env.VOILA_ERROR_STACK === 'true') {
|
|
71
|
+
console.warn(`[VoilaJSX AppKit] Security warning: VOILA_ERROR_STACK=true in production. ` +
|
|
72
|
+
`Stack traces may expose internal application structure. Consider setting to false.`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=defaults.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defaults.js","sourceRoot":"","sources":["../../src/error/defaults.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA6BH;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB;IAC9B,mBAAmB,EAAE,CAAC;IAEtB,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,aAAa,CAAC;IACtD,MAAM,aAAa,GAAG,OAAO,KAAK,aAAa,CAAC;IAChD,MAAM,YAAY,GAAG,OAAO,KAAK,YAAY,CAAC;IAC9C,MAAM,MAAM,GAAG,OAAO,KAAK,MAAM,CAAC;IAElC,OAAO;QACL,oDAAoD;QACpD,QAAQ,EAAE;YACR,UAAU,EAAE,aAAa;YACzB,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,yBAAyB;YACzE,SAAS,EAAE,eAAe;YAC1B,QAAQ,EAAE,WAAW;YACrB,QAAQ,EAAE,UAAU;YACpB,WAAW,EAAE,aAAa,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,cAAc;SACtE;QAED,8CAA8C;QAC9C,UAAU,EAAE;YACV,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB,KAAK,MAAM,IAAI,aAAa;YACpE,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,eAAe,KAAK,OAAO;SACnD;QAED,0BAA0B;QAC1B,WAAW,EAAE;YACX,aAAa;YACb,YAAY;YACZ,MAAM;YACN,OAAO;SACR;KACF,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,SAAS,mBAAmB;IAC1B,sDAAsD;IACtD,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IACjD,IAAI,UAAU,IAAI,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;QACxE,MAAM,IAAI,KAAK,CACb,+BAA+B,UAAU,8BAA8B,CACxE,CAAC;IACJ,CAAC;IAED,qDAAqD;IACrD,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;IAC7C,IAAI,QAAQ,IAAI,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;QACpE,MAAM,IAAI,KAAK,CACb,6BAA6B,QAAQ,8BAA8B,CACpE,CAAC;IACJ,CAAC;IAED,0DAA0D;IAC1D,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC;IACrC,IAAI,OAAO,IAAI,CAAC,CAAC,aAAa,EAAE,YAAY,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QACnF,OAAO,CAAC,IAAI,CACV,wCAAwC,OAAO,KAAK;YACpD,qDAAqD,CACtD,CAAC;IACJ,CAAC;IAED,oCAAoC;IACpC,IAAI,OAAO,KAAK,YAAY,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,KAAK,MAAM,EAAE,CAAC;QACzE,OAAO,CAAC,IAAI,CACV,4EAA4E;YAC5E,oFAAoF,CACrF,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core error class with semantic HTTP status codes and middleware
|
|
3
|
+
* @module @bloomneo/appkit/error
|
|
4
|
+
* @file src/error/error.ts
|
|
5
|
+
*
|
|
6
|
+
* @llm-rule WHEN: Building apps that need semantic HTTP error handling
|
|
7
|
+
* @llm-rule AVOID: Using directly - always get instance via errorClass.get()
|
|
8
|
+
* @llm-rule NOTE: Provides semantic error creation (badRequest, unauthorized) and Express middleware
|
|
9
|
+
*/
|
|
10
|
+
import type { ErrorConfig } from './defaults.js';
|
|
11
|
+
export interface AppError extends Error {
|
|
12
|
+
statusCode: number;
|
|
13
|
+
type: string;
|
|
14
|
+
}
|
|
15
|
+
export interface ExpressRequest {
|
|
16
|
+
[key: string]: any;
|
|
17
|
+
}
|
|
18
|
+
export interface ExpressResponse {
|
|
19
|
+
status: (code: number) => ExpressResponse;
|
|
20
|
+
json: (data: any) => void;
|
|
21
|
+
}
|
|
22
|
+
export interface ExpressNextFunction {
|
|
23
|
+
(error?: any): void;
|
|
24
|
+
}
|
|
25
|
+
export type ExpressErrorHandler = (error: AppError, req: ExpressRequest, res: ExpressResponse, next: ExpressNextFunction) => void;
|
|
26
|
+
export type AsyncRouteHandler = (req: ExpressRequest, res: ExpressResponse, next: ExpressNextFunction) => Promise<any>;
|
|
27
|
+
export interface ErrorHandlerOptions {
|
|
28
|
+
showStack?: boolean;
|
|
29
|
+
logErrors?: boolean;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Error class with semantic HTTP status codes and middleware functionality
|
|
33
|
+
*/
|
|
34
|
+
export declare class ErrorClass {
|
|
35
|
+
config: ErrorConfig;
|
|
36
|
+
constructor(config: ErrorConfig);
|
|
37
|
+
/**
|
|
38
|
+
* Creates a 400 Bad Request error
|
|
39
|
+
* @llm-rule WHEN: Client sends invalid input data (missing fields, wrong format)
|
|
40
|
+
* @llm-rule AVOID: Using for server-side validation errors - use conflict() instead
|
|
41
|
+
* @llm-rule NOTE: EXAMPLES: missing email, invalid JSON, malformed request body
|
|
42
|
+
* @llm-rule NOTE: PATTERN: if (!req.body.email) throw error.badRequest('Email required');
|
|
43
|
+
*/
|
|
44
|
+
badRequest(message?: string): AppError;
|
|
45
|
+
/**
|
|
46
|
+
* Creates a 401 Unauthorized error
|
|
47
|
+
* @llm-rule WHEN: Authentication is required but missing or invalid
|
|
48
|
+
* @llm-rule AVOID: Using for permission issues - use forbidden() for access control
|
|
49
|
+
* @llm-rule NOTE: EXAMPLES: missing token, invalid token, expired session
|
|
50
|
+
* @llm-rule NOTE: PATTERN: if (!token) throw error.unauthorized('Token required');
|
|
51
|
+
*/
|
|
52
|
+
unauthorized(message?: string): AppError;
|
|
53
|
+
/**
|
|
54
|
+
* Creates a 403 Forbidden error
|
|
55
|
+
* @llm-rule WHEN: User is authenticated but lacks permission for the action
|
|
56
|
+
* @llm-rule AVOID: Using for authentication issues - use unauthorized() instead
|
|
57
|
+
* @llm-rule NOTE: EXAMPLES: insufficient role, blocked user, admin-only endpoint
|
|
58
|
+
* @llm-rule NOTE: PATTERN: if (!user.isAdmin) throw error.forbidden('Admin access required');
|
|
59
|
+
*/
|
|
60
|
+
forbidden(message?: string): AppError;
|
|
61
|
+
/**
|
|
62
|
+
* Creates a 404 Not Found error
|
|
63
|
+
* @llm-rule WHEN: Requested resource does not exist
|
|
64
|
+
* @llm-rule AVOID: Using for business logic failures - use conflict() instead
|
|
65
|
+
* @llm-rule NOTE: EXAMPLES: user not found, post not found, missing file
|
|
66
|
+
* @llm-rule NOTE: PATTERN: if (!user) throw error.notFound('User not found');
|
|
67
|
+
*/
|
|
68
|
+
notFound(message?: string): AppError;
|
|
69
|
+
/**
|
|
70
|
+
* Creates a 409 Conflict error
|
|
71
|
+
* @llm-rule WHEN: Business logic conflicts or resource already exists
|
|
72
|
+
* @llm-rule AVOID: Using for validation errors - use badRequest() for input validation
|
|
73
|
+
* @llm-rule NOTE: EXAMPLES: email already exists, duplicate username, state conflicts
|
|
74
|
+
* @llm-rule NOTE: PATTERN: if (existingUser) throw error.conflict('Email already registered');
|
|
75
|
+
*/
|
|
76
|
+
conflict(message?: string): AppError;
|
|
77
|
+
/**
|
|
78
|
+
* Creates a 500 Server Error
|
|
79
|
+
* @llm-rule WHEN: Internal server failures like database errors, external API failures
|
|
80
|
+
* @llm-rule AVOID: Using for business logic issues - use appropriate 4xx errors instead
|
|
81
|
+
* @llm-rule NOTE: EXAMPLES: database connection failure, external API timeout, file system errors
|
|
82
|
+
* @llm-rule NOTE: PATTERN: catch (dbError) { throw error.serverError('Database unavailable'); }
|
|
83
|
+
*/
|
|
84
|
+
serverError(message?: string): AppError;
|
|
85
|
+
/**
|
|
86
|
+
* Creates a custom error with any status code
|
|
87
|
+
* @llm-rule WHEN: Need custom HTTP status codes not covered by semantic methods
|
|
88
|
+
* @llm-rule AVOID: Using for standard HTTP codes - use semantic methods instead
|
|
89
|
+
* @llm-rule NOTE: EXAMPLES: 429 rate limit, 503 service unavailable, 418 teapot
|
|
90
|
+
* @llm-rule NOTE: PATTERN: error.createError(429, 'Rate limit exceeded', 'RATE_LIMIT');
|
|
91
|
+
*/
|
|
92
|
+
createError(statusCode: number, message: string, type?: string): AppError;
|
|
93
|
+
/**
|
|
94
|
+
* Creates production-ready Express error handling middleware
|
|
95
|
+
* @llm-rule WHEN: Setting up Express app error handling - use as last middleware
|
|
96
|
+
* @llm-rule AVOID: Using multiple error handlers - this should be the final middleware
|
|
97
|
+
* @llm-rule NOTE: MIDDLEWARE SETUP: app.use(error.handleErrors()); // Must be LAST
|
|
98
|
+
* @llm-rule NOTE: AUTO-FEATURES: dev vs prod responses, stack trace hiding, error logging
|
|
99
|
+
*/
|
|
100
|
+
handleErrors(options?: ErrorHandlerOptions): ExpressErrorHandler;
|
|
101
|
+
/**
|
|
102
|
+
* Wraps async route handlers to catch errors automatically
|
|
103
|
+
* @llm-rule WHEN: Creating async Express route handlers that might throw errors
|
|
104
|
+
* @llm-rule AVOID: Manual try/catch in every route - this handles it automatically
|
|
105
|
+
* @llm-rule NOTE: ASYNC PATTERN: app.post('/route', error.asyncRoute(async (req, res) => {...}));
|
|
106
|
+
* @llm-rule NOTE: ERROR FLOW: thrown errors → automatically caught → sent to handleErrors middleware
|
|
107
|
+
*/
|
|
108
|
+
asyncRoute(fn: AsyncRouteHandler): (req: ExpressRequest, res: ExpressResponse, next: ExpressNextFunction) => void;
|
|
109
|
+
/**
|
|
110
|
+
* Checks if error is a 4xx client error
|
|
111
|
+
* @llm-rule WHEN: Need to categorize errors for logging or metrics
|
|
112
|
+
* @llm-rule AVOID: Manual status code checking - this handles the logic
|
|
113
|
+
* @llm-rule NOTE: CLIENT ERRORS: 400-499 status codes (user's fault)
|
|
114
|
+
*/
|
|
115
|
+
isClientError(error: AppError): boolean;
|
|
116
|
+
/**
|
|
117
|
+
* Checks if error is a 5xx server error
|
|
118
|
+
* @llm-rule WHEN: Need to categorize errors for monitoring or alerting
|
|
119
|
+
* @llm-rule AVOID: Manual status code checking - this handles the logic
|
|
120
|
+
* @llm-rule NOTE: SERVER ERRORS: 500-599 status codes (server's fault)
|
|
121
|
+
*/
|
|
122
|
+
isServerError(error: AppError): boolean;
|
|
123
|
+
/**
|
|
124
|
+
* Gets current environment detection info
|
|
125
|
+
* @llm-rule WHEN: Need to check current environment configuration
|
|
126
|
+
* @llm-rule AVOID: Direct process.env access - this provides parsed config
|
|
127
|
+
*/
|
|
128
|
+
getEnvironmentInfo(): {
|
|
129
|
+
isDevelopment: boolean;
|
|
130
|
+
isProduction: boolean;
|
|
131
|
+
nodeEnv: string;
|
|
132
|
+
};
|
|
133
|
+
/**
|
|
134
|
+
* Gets current error configuration
|
|
135
|
+
* @llm-rule WHEN: Debugging error setup or inspecting current settings
|
|
136
|
+
* @llm-rule AVOID: Accessing config directly - this provides clean interface
|
|
137
|
+
*/
|
|
138
|
+
getConfig(): ErrorConfig;
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=error.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../../src/error/error.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD,MAAM,WAAW,QAAS,SAAQ,KAAK;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,cAAc;IAC7B,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,eAAe,CAAC;IAC1C,IAAI,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,mBAAmB;IAClC,CAAC,KAAK,CAAC,EAAE,GAAG,GAAG,IAAI,CAAC;CACrB;AAED,MAAM,MAAM,mBAAmB,GAAG,CAChC,KAAK,EAAE,QAAQ,EACf,GAAG,EAAE,cAAc,EACnB,GAAG,EAAE,eAAe,EACpB,IAAI,EAAE,mBAAmB,KACtB,IAAI,CAAC;AAEV,MAAM,MAAM,iBAAiB,GAAG,CAC9B,GAAG,EAAE,cAAc,EACnB,GAAG,EAAE,eAAe,EACpB,IAAI,EAAE,mBAAmB,KACtB,OAAO,CAAC,GAAG,CAAC,CAAC;AAElB,MAAM,WAAW,mBAAmB;IAClC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;GAEG;AACH,qBAAa,UAAU;IACd,MAAM,EAAE,WAAW,CAAC;gBAEf,MAAM,EAAE,WAAW;IAI/B;;;;;;OAMG;IACH,UAAU,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,QAAQ;IAOtC;;;;;;OAMG;IACH,YAAY,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,QAAQ;IAOxC;;;;;;OAMG;IACH,SAAS,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,QAAQ;IAOrC;;;;;;OAMG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,QAAQ;IAOpC;;;;;;OAMG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,QAAQ;IAOpC;;;;;;OAMG;IACH,WAAW,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,QAAQ;IAOvC;;;;;;OAMG;IACH,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,QAAQ;IAOzE;;;;;;OAMG;IACH,YAAY,CAAC,OAAO,GAAE,mBAAwB,GAAG,mBAAmB;IAyCpE;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,EAAE,iBAAiB,GAAG,CAAC,GAAG,EAAE,cAAc,EAAE,GAAG,EAAE,eAAe,EAAE,IAAI,EAAE,mBAAmB,KAAK,IAAI;IAMjH;;;;;OAKG;IACH,aAAa,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO;IAIvC;;;;;OAKG;IACH,aAAa,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO;IAIvC;;;;OAIG;IACH,kBAAkB,IAAI;QAAE,aAAa,EAAE,OAAO,CAAC;QAAC,YAAY,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE;IAQxF;;;;OAIG;IACH,SAAS,IAAI,WAAW;CAGzB"}
|