alepha 0.9.5 → 0.10.0

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/email.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as _alepha_core1 from "alepha";
2
2
  import { Descriptor, KIND, Service, Static, TSchema } from "alepha";
3
- import * as _alepha_logger0 from "alepha/logger";
3
+ import * as _alepha_logger1 from "alepha/logger";
4
4
  import { Transporter } from "nodemailer";
5
5
 
6
6
  //#region src/providers/EmailProvider.d.ts
@@ -30,7 +30,7 @@ interface EmailRecord {
30
30
  sentAt: Date;
31
31
  }
32
32
  declare class MemoryEmailProvider implements EmailProvider {
33
- protected readonly log: _alepha_logger0.Logger;
33
+ protected readonly log: _alepha_logger1.Logger;
34
34
  protected emails: EmailRecord[];
35
35
  send(to: string, subject: string, body: string): Promise<void>;
36
36
  /**
@@ -87,27 +87,109 @@ declare class TemplateService {
87
87
  //#endregion
88
88
  //#region src/descriptors/$email.d.ts
89
89
  /**
90
- * Create an email descriptor for sending templated emails.
90
+ * Creates an email descriptor for sending type-safe templated emails.
91
91
  *
92
- * @example
93
- * ```ts
94
- * import { $email } from "alepha/email";
95
- * import { t } from "alepha";
92
+ * The $email descriptor provides a powerful templating system for creating and sending emails
93
+ * with full type safety and validation. It supports multiple email providers, template variable
94
+ * validation, and automatic HTML rendering.
96
95
  *
97
- * class App {
98
- * welcome = $email({
99
- * subject: "Welcome {{name}}!",
100
- * body: "<h1>Welcome {{name}}!</h1><p>Your role is {{role}}.</p>",
101
- * schema: t.object({
102
- * name: t.string(),
103
- * role: t.string()
104
- * })
105
- * });
96
+ * **Template Engine**
97
+ * - Simple {{variable}} syntax for dynamic content
98
+ * - Automatic template variable validation at runtime
99
+ * - Support for nested object properties in templates
100
+ * - HTML email support with rich formatting
106
101
  *
107
- * async sendWelcome(userEmail: string, name: string, role: string) {
108
- * await this.welcome.send(userEmail, { name, role });
109
- * }
110
- * }
102
+ * **Type Safety**
103
+ * - Full TypeScript support with schema validation using TypeBox
104
+ * - Compile-time type checking for template variables
105
+ * - Runtime validation of email data before sending
106
+ * - Automatic type inference from schema definitions
107
+ *
108
+ * **Provider Flexibility**
109
+ * - Memory provider for development and testing
110
+ * - Support for SMTP, SendGrid, AWS SES, and other providers
111
+ * - Custom provider implementation for specialized services
112
+ * - Automatic fallback and error handling
113
+ *
114
+ * **Template Management**
115
+ * - Reusable email templates across your application
116
+ * - Centralized template configuration and maintenance
117
+ * - Template variable documentation through schemas
118
+ * - Easy testing and preview capabilities
119
+ *
120
+ * **Development Experience**
121
+ * - Clear error messages for missing template variables
122
+ * - Comprehensive logging for debugging email delivery
123
+ * - Memory provider captures emails for testing
124
+ * - Template validation before sending
125
+ *
126
+ * @example Welcome email template
127
+ * ```typescript
128
+ * const welcomeEmail = $email({
129
+ * subject: "Welcome to {{companyName}}, {{firstName}}!",
130
+ * body: `
131
+ * <h1>Welcome {{firstName}} {{lastName}}!</h1>
132
+ * <p>Thank you for joining {{companyName}}.</p>
133
+ * <p>Your account role is: <strong>{{role}}</strong></p>
134
+ * <p>Get started by visiting your <a href="{{dashboardUrl}}">dashboard</a>.</p>
135
+ * `,
136
+ * schema: t.object({
137
+ * firstName: t.string(),
138
+ * lastName: t.string(),
139
+ * companyName: t.string(),
140
+ * role: t.enum(["admin", "user", "manager"]),
141
+ * dashboardUrl: t.string()
142
+ * })
143
+ * });
144
+ *
145
+ * // Send with full type safety
146
+ * await welcomeEmail.send("user@example.com", {
147
+ * firstName: "John",
148
+ * lastName: "Doe",
149
+ * companyName: "Acme Corp",
150
+ * role: "user",
151
+ * dashboardUrl: "https://app.acme.com/dashboard"
152
+ * });
153
+ * ```
154
+ *
155
+ * @example Order confirmation email
156
+ * ```typescript
157
+ * const orderConfirmation = $email({
158
+ * subject: "Order #{{orderNumber}} confirmed - {{totalAmount}}",
159
+ * body: `
160
+ * <h1>Order Confirmed!</h1>
161
+ * <p>Hi {{customerName}},</p>
162
+ * <p>Your order #{{orderNumber}} has been confirmed.</p>
163
+ * <h2>Order Details:</h2>
164
+ * <p><strong>Total: {{totalAmount}}</strong></p>
165
+ * <p>Estimated delivery: {{deliveryDate}}</p>
166
+ * `,
167
+ * schema: t.object({
168
+ * customerName: t.string(),
169
+ * orderNumber: t.string(),
170
+ * totalAmount: t.string(),
171
+ * deliveryDate: t.string()
172
+ * })
173
+ * });
174
+ * ```
175
+ *
176
+ * @example Development with memory provider
177
+ * ```typescript
178
+ * const testEmail = $email({
179
+ * subject: "Test: {{subject}}",
180
+ * body: "<p>{{message}}</p>",
181
+ * provider: "memory", // Captures emails for testing
182
+ * schema: t.object({
183
+ * subject: t.string(),
184
+ * message: t.string()
185
+ * })
186
+ * });
187
+ *
188
+ * // In tests - emails are captured, not actually sent
189
+ * await testEmail.send("test@example.com", {
190
+ * subject: "Unit Test",
191
+ * message: "This email was captured for testing"
192
+ * });
111
193
  * ```
112
194
  */
113
195
  declare const $email: {
@@ -142,7 +224,7 @@ interface EmailDescriptorOptions<T extends TSchema> {
142
224
  provider?: Service<EmailProvider> | "memory";
143
225
  }
144
226
  declare class EmailDescriptor<T extends TSchema> extends Descriptor<EmailDescriptorOptions<T>> {
145
- protected readonly log: _alepha_logger0.Logger;
227
+ protected readonly log: _alepha_logger1.Logger;
146
228
  protected readonly templateService: TemplateService;
147
229
  readonly provider: EmailProvider | MemoryEmailProvider;
148
230
  get name(): string;
@@ -170,7 +252,7 @@ interface LocalEmailProviderOptions {
170
252
  directory?: string;
171
253
  }
172
254
  declare class LocalEmailProvider implements EmailProvider {
173
- protected readonly log: _alepha_logger0.Logger;
255
+ protected readonly log: _alepha_logger1.Logger;
174
256
  protected readonly directory: string;
175
257
  constructor(options?: LocalEmailProviderOptions);
176
258
  send(to: string, subject: string, body: string): Promise<void>;
@@ -210,7 +292,7 @@ declare class NodemailerEmailProvider implements EmailProvider {
210
292
  EMAIL_FROM: string;
211
293
  EMAIL_SECURE: boolean;
212
294
  };
213
- protected readonly log: _alepha_logger0.Logger;
295
+ protected readonly log: _alepha_logger1.Logger;
214
296
  protected transporter: Transporter;
215
297
  protected fromAddress: string;
216
298
  readonly options: NodemailerEmailProviderOptions;
package/logger.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as _alepha_core0 from "alepha";
2
2
  import { Alepha, KIND, LogLevel, LoggerInterface, Static } from "alepha";
3
- import * as _sinclair_typebox0 from "@sinclair/typebox";
3
+ import * as typebox0 from "typebox";
4
4
 
5
5
  //#region src/providers/LogDestinationProvider.d.ts
6
6
  declare abstract class LogDestinationProvider {
@@ -27,6 +27,7 @@ declare class Logger implements LoggerInterface {
27
27
  get context(): string | undefined;
28
28
  get level(): string;
29
29
  parseLevel(level: string, app: string): LogLevel;
30
+ private matchesPattern;
30
31
  asLogLevel(something: string): LogLevel;
31
32
  error(message: string, data?: unknown): void;
32
33
  warn(message: string, data?: unknown): void;
@@ -76,12 +77,7 @@ interface LoggerDescriptorOptions {
76
77
  //#endregion
77
78
  //#region src/providers/ConsoleColorProvider.d.ts
78
79
  declare class ConsoleColorProvider {
79
- protected readonly env: {
80
- NO_COLOR?: string | undefined;
81
- FORCE_COLOR?: string | undefined;
82
- };
83
- protected readonly alepha: Alepha;
84
- readonly colors: {
80
+ static readonly COLORS: {
85
81
  reset: string;
86
82
  grey: string;
87
83
  red: string;
@@ -98,10 +94,15 @@ declare class ConsoleColorProvider {
98
94
  debug: string;
99
95
  trace: string;
100
96
  };
97
+ protected readonly env: {
98
+ NO_COLOR?: string | undefined;
99
+ FORCE_COLOR?: string | undefined;
100
+ };
101
+ protected readonly alepha: Alepha;
101
102
  protected enabled: boolean;
102
103
  constructor();
103
104
  isEnabled(): boolean;
104
- colorize(color: keyof typeof (void 0).colors, text: string, reset?: string): string;
105
+ colorize(color: keyof typeof ConsoleColorProvider.COLORS, text: string, reset?: string): string;
105
106
  }
106
107
  //#endregion
107
108
  //#region src/providers/ConsoleDestinationProvider.d.ts
@@ -168,6 +169,22 @@ declare class SimpleFormatterProvider extends LogFormatterProvider {
168
169
  * - SimpleFormatterProvider: formats logs as simple text (with colors when possible).
169
170
  * - RawFormatterProvider: formats logs as raw text without any formatting.
170
171
  *
172
+ * ### Event Emission
173
+ *
174
+ * The logger emits 'log' events that can be listened to by external code, allowing for custom log processing and destinations.
175
+ *
176
+ * ```ts
177
+ * class CustomDestination {
178
+ * onLog = $hook({
179
+ * on: "log",
180
+ * handler: (ev) => {
181
+ * // ev.message (formatted message)
182
+ * // ev.entry (level, raw message, ...)
183
+ * }
184
+ * });
185
+ * }
186
+ * ```
187
+ *
171
188
  * ### Log Level
172
189
  *
173
190
  * You can configure the log level and format via environment variables:
@@ -181,11 +198,22 @@ declare class SimpleFormatterProvider extends LogFormatterProvider {
181
198
  *
182
199
  * Log level is also available in the state as `logLevel`, which can be used to dynamically change the log level at runtime.
183
200
  * ```ts
184
- * alepha.state("logLevel", "debug");
201
+ * alepha.state.set("logLevel", "debug");
185
202
  * ```
186
203
  *
187
204
  * Log level is $module aware, meaning you can set different log levels for different modules.
188
- * For example, you can set `LOG_LEVEL=my.module.name:debug,info` to set the log level to debug for `my.module.name` and info for all other modules.
205
+ *
206
+ * **Module-specific configuration:**
207
+ * - `LOG_LEVEL=my.module.name:debug,info` - debug for `my.module.name` (and submodules), info for others
208
+ * - `LOG_LEVEL=alepha:trace,my.app:error,info` - trace for alepha modules, error for my.app modules, info for others
209
+ *
210
+ * **Wildcard patterns (NEW):**
211
+ * - `LOG_LEVEL=alepha.*:debug,info` - debug for all alepha submodules
212
+ * - `LOG_LEVEL=*.test:silent,*.core:trace,info` - silent for test modules, trace for core modules
213
+ *
214
+ * **Robust parsing:**
215
+ * - Empty parts are gracefully skipped: `LOG_LEVEL=",,debug,,"` works fine
216
+ * - Better error messages: "Invalid log level 'bad' for module pattern 'alepha'"
189
217
  */
190
218
  declare const AlephaLogger: _alepha_core0.Service<_alepha_core0.Module>;
191
219
  declare const envSchema: _alepha_core0.TObject<{
@@ -212,16 +240,21 @@ declare const envSchema: _alepha_core0.TObject<{
212
240
  * - "text" - Simple text format, human-readable, with colors. {@link SimpleFormatterProvider}
213
241
  * - "raw" - Raw format, no formatting, just the message. {@link RawFormatterProvider}
214
242
  */
215
- LOG_FORMAT: _alepha_core0.TOptional<_sinclair_typebox0.TUnsafe<"json" | "text" | "raw">>;
243
+ LOG_FORMAT: _alepha_core0.TOptional<typebox0.TUnsafe<"json" | "text" | "raw">>;
216
244
  }>;
217
245
  declare module "alepha" {
218
246
  interface Env extends Partial<Static<typeof envSchema>> {}
219
247
  interface State {
220
248
  logLevel?: string;
221
249
  }
250
+ interface Hooks {
251
+ log: {
252
+ message: string;
253
+ entry: LogEntry;
254
+ };
255
+ }
222
256
  }
223
257
  //# sourceMappingURL=index.d.ts.map
224
-
225
258
  //#endregion
226
259
  export { $logger, AlephaLogger, ConsoleColorProvider, ConsoleDestinationProvider, JsonFormatterProvider, LogDestinationProvider, LogEntry, LogFormatterProvider, Logger, LoggerDescriptorOptions, MemoryDestinationProvider, SimpleFormatterProvider };
227
260
  //# sourceMappingURL=index.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "alepha",
3
- "version": "0.9.5",
3
+ "version": "0.10.0",
4
4
  "type": "module",
5
5
  "engines": {
6
6
  "node": ">=22.0.0"
@@ -15,52 +15,51 @@
15
15
  "main": "./core.js",
16
16
  "types": "./core.d.ts",
17
17
  "dependencies": {
18
- "@alepha/batch": "0.9.5",
19
- "@alepha/bucket": "0.9.5",
20
- "@alepha/cache": "0.9.5",
21
- "@alepha/cache-redis": "0.9.5",
22
- "@alepha/command": "0.9.5",
23
- "@alepha/core": "0.9.5",
24
- "@alepha/datetime": "0.9.5",
25
- "@alepha/email": "0.9.5",
26
- "@alepha/file": "0.9.5",
27
- "@alepha/lock": "0.9.5",
28
- "@alepha/lock-redis": "0.9.5",
29
- "@alepha/logger": "0.9.5",
30
- "@alepha/postgres": "0.9.5",
31
- "@alepha/queue": "0.9.5",
32
- "@alepha/queue-redis": "0.9.5",
33
- "@alepha/react": "0.9.5",
34
- "@alepha/react-auth": "0.9.5",
35
- "@alepha/react-form": "0.9.5",
36
- "@alepha/react-head": "0.9.5",
37
- "@alepha/react-i18n": "0.9.5",
38
- "@alepha/redis": "0.9.5",
39
- "@alepha/retry": "0.9.5",
40
- "@alepha/router": "0.9.5",
41
- "@alepha/scheduler": "0.9.5",
42
- "@alepha/security": "0.9.5",
43
- "@alepha/server": "0.9.5",
44
- "@alepha/server-cache": "0.9.5",
45
- "@alepha/server-compress": "0.9.5",
46
- "@alepha/server-cookies": "0.9.5",
47
- "@alepha/server-cors": "0.9.5",
48
- "@alepha/server-health": "0.9.5",
49
- "@alepha/server-helmet": "0.9.5",
50
- "@alepha/server-links": "0.9.5",
51
- "@alepha/server-metrics": "0.9.5",
52
- "@alepha/server-multipart": "0.9.5",
53
- "@alepha/server-proxy": "0.9.5",
54
- "@alepha/server-security": "0.9.5",
55
- "@alepha/server-static": "0.9.5",
56
- "@alepha/server-swagger": "0.9.5",
57
- "@alepha/topic": "0.9.5",
58
- "@alepha/topic-redis": "0.9.5",
59
- "@alepha/vite": "0.9.5",
60
- "react": "^19.1.1"
18
+ "@alepha/batch": "0.10.0",
19
+ "@alepha/bucket": "0.10.0",
20
+ "@alepha/cache": "0.10.0",
21
+ "@alepha/cache-redis": "0.10.0",
22
+ "@alepha/command": "0.10.0",
23
+ "@alepha/core": "0.10.0",
24
+ "@alepha/datetime": "0.10.0",
25
+ "@alepha/email": "0.10.0",
26
+ "@alepha/file": "0.10.0",
27
+ "@alepha/lock": "0.10.0",
28
+ "@alepha/lock-redis": "0.10.0",
29
+ "@alepha/logger": "0.10.0",
30
+ "@alepha/postgres": "0.10.0",
31
+ "@alepha/queue": "0.10.0",
32
+ "@alepha/queue-redis": "0.10.0",
33
+ "@alepha/react": "0.10.0",
34
+ "@alepha/react-auth": "0.10.0",
35
+ "@alepha/react-form": "0.10.0",
36
+ "@alepha/react-head": "0.10.0",
37
+ "@alepha/react-i18n": "0.10.0",
38
+ "@alepha/redis": "0.10.0",
39
+ "@alepha/retry": "0.10.0",
40
+ "@alepha/router": "0.10.0",
41
+ "@alepha/scheduler": "0.10.0",
42
+ "@alepha/security": "0.10.0",
43
+ "@alepha/server": "0.10.0",
44
+ "@alepha/server-cache": "0.10.0",
45
+ "@alepha/server-compress": "0.10.0",
46
+ "@alepha/server-cookies": "0.10.0",
47
+ "@alepha/server-cors": "0.10.0",
48
+ "@alepha/server-health": "0.10.0",
49
+ "@alepha/server-helmet": "0.10.0",
50
+ "@alepha/server-links": "0.10.0",
51
+ "@alepha/server-metrics": "0.10.0",
52
+ "@alepha/server-multipart": "0.10.0",
53
+ "@alepha/server-proxy": "0.10.0",
54
+ "@alepha/server-security": "0.10.0",
55
+ "@alepha/server-static": "0.10.0",
56
+ "@alepha/server-swagger": "0.10.0",
57
+ "@alepha/topic": "0.10.0",
58
+ "@alepha/topic-redis": "0.10.0",
59
+ "@alepha/vite": "0.10.0"
61
60
  },
62
61
  "devDependencies": {
63
- "tsdown": "^0.15.1"
62
+ "tsdown": "^0.15.3"
64
63
  },
65
64
  "scripts": {
66
65
  "build": "node build.ts"
@@ -70,6 +69,18 @@
70
69
  "**/*.cjs",
71
70
  "**/*.d.ts"
72
71
  ],
72
+ "peerDependencies": {
73
+ "react": "*",
74
+ "react-dom": "*"
75
+ },
76
+ "peerDependenciesMeta": {
77
+ "react": {
78
+ "optional": true
79
+ },
80
+ "react-dom": {
81
+ "optional": true
82
+ }
83
+ },
73
84
  "exports": {
74
85
  ".": {
75
86
  "import": "./core.js",