@guren/server 0.2.0-alpha.7 → 1.0.0-rc.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.
Files changed (54) hide show
  1. package/dist/Application-DtWDHXr1.d.ts +2110 -0
  2. package/dist/BroadcastManager-AkIWUGJo.d.ts +466 -0
  3. package/dist/CacheManager-BkvHEOZX.d.ts +244 -0
  4. package/dist/ConsoleKernel-CqCVrdZs.d.ts +207 -0
  5. package/dist/EventManager-CmIoLt7r.d.ts +207 -0
  6. package/dist/Gate-CNkBYf8m.d.ts +268 -0
  7. package/dist/HealthManager-DUyMIzsZ.d.ts +141 -0
  8. package/dist/I18nManager-Dtgzsf5n.d.ts +270 -0
  9. package/dist/LogManager-7mxnkaPM.d.ts +256 -0
  10. package/dist/MailManager-DpMvYiP9.d.ts +292 -0
  11. package/dist/Scheduler-BstvSca7.d.ts +469 -0
  12. package/dist/StorageManager-oZTHqaza.d.ts +337 -0
  13. package/dist/api-token-JOif2CtG.d.ts +1792 -0
  14. package/dist/app-key-CsBfRC_Q.d.ts +214 -0
  15. package/dist/auth/index.d.ts +418 -0
  16. package/dist/auth/index.js +6742 -0
  17. package/dist/authorization/index.d.ts +129 -0
  18. package/dist/authorization/index.js +621 -0
  19. package/dist/broadcasting/index.d.ts +233 -0
  20. package/dist/broadcasting/index.js +907 -0
  21. package/dist/cache/index.d.ts +233 -0
  22. package/dist/cache/index.js +817 -0
  23. package/dist/encryption/index.d.ts +222 -0
  24. package/dist/encryption/index.js +602 -0
  25. package/dist/events/index.d.ts +155 -0
  26. package/dist/events/index.js +330 -0
  27. package/dist/health/index.d.ts +185 -0
  28. package/dist/health/index.js +379 -0
  29. package/dist/i18n/index.d.ts +101 -0
  30. package/dist/i18n/index.js +597 -0
  31. package/dist/index-9_Jzj5jo.d.ts +7 -0
  32. package/dist/index.d.ts +2628 -619
  33. package/dist/index.js +22229 -3116
  34. package/dist/lambda/index.d.ts +156 -0
  35. package/dist/lambda/index.js +91 -0
  36. package/dist/logging/index.d.ts +50 -0
  37. package/dist/logging/index.js +557 -0
  38. package/dist/mail/index.d.ts +288 -0
  39. package/dist/mail/index.js +695 -0
  40. package/dist/mcp/index.d.ts +139 -0
  41. package/dist/mcp/index.js +382 -0
  42. package/dist/notifications/index.d.ts +271 -0
  43. package/dist/notifications/index.js +741 -0
  44. package/dist/queue/index.d.ts +423 -0
  45. package/dist/queue/index.js +958 -0
  46. package/dist/runtime/index.d.ts +93 -0
  47. package/dist/runtime/index.js +834 -0
  48. package/dist/scheduling/index.d.ts +41 -0
  49. package/dist/scheduling/index.js +836 -0
  50. package/dist/storage/index.d.ts +196 -0
  51. package/dist/storage/index.js +832 -0
  52. package/dist/vite/index.js +203 -3
  53. package/package.json +93 -6
  54. package/dist/chunk-FK2XQSBF.js +0 -160
@@ -0,0 +1,695 @@
1
+ // src/mail/transports/SmtpTransport.ts
2
+ import nodemailer from "nodemailer";
3
+ function formatAddress(addr) {
4
+ if (addr.name) {
5
+ return `"${addr.name}" <${addr.email}>`;
6
+ }
7
+ return addr.email;
8
+ }
9
+ var SmtpTransport = class {
10
+ name = "smtp";
11
+ // Using any to avoid complex nodemailer type gymnastics
12
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
13
+ transporter;
14
+ constructor(options) {
15
+ this.transporter = nodemailer.createTransport({
16
+ host: options.host,
17
+ port: options.port ?? 587,
18
+ secure: options.secure ?? false,
19
+ auth: options.auth,
20
+ pool: options.pool ?? true,
21
+ maxConnections: options.maxConnections ?? 5
22
+ });
23
+ }
24
+ /**
25
+ * Send an email via SMTP.
26
+ */
27
+ async send(message) {
28
+ try {
29
+ const mailOptions = {
30
+ from: message.from ? formatAddress(message.from) : void 0,
31
+ to: message.to.map(formatAddress).join(", "),
32
+ cc: message.cc?.map(formatAddress).join(", "),
33
+ bcc: message.bcc?.map(formatAddress).join(", "),
34
+ replyTo: message.replyTo ? formatAddress(message.replyTo) : void 0,
35
+ subject: message.subject,
36
+ text: message.text,
37
+ html: message.html,
38
+ attachments: message.attachments?.map((a) => ({
39
+ filename: a.filename,
40
+ content: a.content,
41
+ path: a.path,
42
+ contentType: a.contentType,
43
+ cid: a.cid
44
+ })),
45
+ headers: message.headers
46
+ };
47
+ const result = await this.transporter.sendMail(mailOptions);
48
+ return {
49
+ success: true,
50
+ messageId: result.messageId,
51
+ response: result.response
52
+ };
53
+ } catch (error) {
54
+ return {
55
+ success: false,
56
+ error: error instanceof Error ? error.message : String(error)
57
+ };
58
+ }
59
+ }
60
+ /**
61
+ * Verify SMTP connection.
62
+ */
63
+ async verify() {
64
+ try {
65
+ await this.transporter.verify();
66
+ return true;
67
+ } catch {
68
+ return false;
69
+ }
70
+ }
71
+ /**
72
+ * Close the transport.
73
+ */
74
+ close() {
75
+ this.transporter.close();
76
+ }
77
+ };
78
+
79
+ // src/mail/transports/ResendTransport.ts
80
+ var ResendTransport = class {
81
+ name = "resend";
82
+ apiKey;
83
+ baseUrl = "https://api.resend.com";
84
+ constructor(options) {
85
+ this.apiKey = options.apiKey;
86
+ }
87
+ /**
88
+ * Format email address for Resend API.
89
+ */
90
+ formatAddress(addr) {
91
+ if (addr.name) {
92
+ return `${addr.name} <${addr.email}>`;
93
+ }
94
+ return addr.email;
95
+ }
96
+ /**
97
+ * Send an email via Resend API.
98
+ */
99
+ async send(message) {
100
+ try {
101
+ const payload = {
102
+ from: message.from ? this.formatAddress(message.from) : void 0,
103
+ to: message.to.map((a) => this.formatAddress(a)),
104
+ subject: message.subject
105
+ };
106
+ if (message.cc?.length) {
107
+ payload.cc = message.cc.map((a) => this.formatAddress(a));
108
+ }
109
+ if (message.bcc?.length) {
110
+ payload.bcc = message.bcc.map((a) => this.formatAddress(a));
111
+ }
112
+ if (message.replyTo) {
113
+ payload.reply_to = this.formatAddress(message.replyTo);
114
+ }
115
+ if (message.text) {
116
+ payload.text = message.text;
117
+ }
118
+ if (message.html) {
119
+ payload.html = message.html;
120
+ }
121
+ if (message.attachments?.length) {
122
+ payload.attachments = message.attachments.map((a) => ({
123
+ filename: a.filename,
124
+ content: a.content instanceof Buffer ? a.content.toString("base64") : a.content,
125
+ content_type: a.contentType
126
+ }));
127
+ }
128
+ if (message.headers) {
129
+ payload.headers = message.headers;
130
+ }
131
+ const response = await fetch(`${this.baseUrl}/emails`, {
132
+ method: "POST",
133
+ headers: {
134
+ "Content-Type": "application/json",
135
+ Authorization: `Bearer ${this.apiKey}`
136
+ },
137
+ body: JSON.stringify(payload)
138
+ });
139
+ if (!response.ok) {
140
+ const errorData = await response.json();
141
+ return {
142
+ success: false,
143
+ error: errorData.message || `HTTP ${response.status}`
144
+ };
145
+ }
146
+ const data = await response.json();
147
+ return {
148
+ success: true,
149
+ messageId: data.id,
150
+ response: `Message sent with ID: ${data.id}`
151
+ };
152
+ } catch (error) {
153
+ return {
154
+ success: false,
155
+ error: error instanceof Error ? error.message : String(error)
156
+ };
157
+ }
158
+ }
159
+ };
160
+
161
+ // src/mail/transports/MemoryTransport.ts
162
+ var MemoryTransport = class {
163
+ name = "memory";
164
+ messages = [];
165
+ simulateFailure;
166
+ failureMessage;
167
+ constructor(options = {}) {
168
+ this.simulateFailure = options.simulateFailure ?? false;
169
+ this.failureMessage = options.failureMessage ?? "Simulated email failure";
170
+ }
171
+ /**
172
+ * Send an email (stores in memory).
173
+ */
174
+ async send(message) {
175
+ if (this.simulateFailure) {
176
+ return {
177
+ success: false,
178
+ error: this.failureMessage
179
+ };
180
+ }
181
+ const messageId = `memory-${Date.now()}-${Math.random().toString(36).slice(2)}`;
182
+ this.messages.push({ ...message });
183
+ return {
184
+ success: true,
185
+ messageId,
186
+ response: "Message stored in memory"
187
+ };
188
+ }
189
+ /**
190
+ * Get all sent messages.
191
+ */
192
+ getMessages() {
193
+ return [...this.messages];
194
+ }
195
+ /**
196
+ * Get the last sent message.
197
+ */
198
+ getLastMessage() {
199
+ return this.messages[this.messages.length - 1];
200
+ }
201
+ /**
202
+ * Find messages by recipient email.
203
+ */
204
+ findByRecipient(email) {
205
+ return this.messages.filter(
206
+ (m) => m.to.some((addr) => addr.email.toLowerCase() === email.toLowerCase())
207
+ );
208
+ }
209
+ /**
210
+ * Find messages by subject.
211
+ */
212
+ findBySubject(subject) {
213
+ return this.messages.filter(
214
+ (m) => m.subject.toLowerCase().includes(subject.toLowerCase())
215
+ );
216
+ }
217
+ /**
218
+ * Check if any message was sent to a recipient.
219
+ */
220
+ hasSentTo(email) {
221
+ return this.findByRecipient(email).length > 0;
222
+ }
223
+ /**
224
+ * Check if any message was sent with a subject.
225
+ */
226
+ hasSentWithSubject(subject) {
227
+ return this.findBySubject(subject).length > 0;
228
+ }
229
+ /**
230
+ * Get the count of sent messages.
231
+ */
232
+ count() {
233
+ return this.messages.length;
234
+ }
235
+ /**
236
+ * Clear all stored messages.
237
+ */
238
+ clear() {
239
+ this.messages = [];
240
+ }
241
+ /**
242
+ * Set whether to simulate failures.
243
+ */
244
+ setSimulateFailure(simulate, message) {
245
+ this.simulateFailure = simulate;
246
+ if (message) {
247
+ this.failureMessage = message;
248
+ }
249
+ }
250
+ /**
251
+ * Assert that a message was sent to a recipient.
252
+ * Throws if no message was found.
253
+ */
254
+ assertSentTo(email) {
255
+ if (!this.hasSentTo(email)) {
256
+ throw new Error(`No email was sent to ${email}`);
257
+ }
258
+ }
259
+ /**
260
+ * Assert that a message was sent with a subject.
261
+ * Throws if no message was found.
262
+ */
263
+ assertSentWithSubject(subject) {
264
+ if (!this.hasSentWithSubject(subject)) {
265
+ throw new Error(`No email was sent with subject containing "${subject}"`);
266
+ }
267
+ }
268
+ /**
269
+ * Assert that exactly n messages were sent.
270
+ * Throws if count doesn't match.
271
+ */
272
+ assertSentCount(count) {
273
+ if (this.messages.length !== count) {
274
+ throw new Error(`Expected ${count} emails to be sent, but got ${this.messages.length}`);
275
+ }
276
+ }
277
+ };
278
+
279
+ // src/mail/MailManager.ts
280
+ var MailManager = class {
281
+ defaultTransportName;
282
+ defaultFrom;
283
+ transportFactories = /* @__PURE__ */ new Map();
284
+ resolvedTransports = /* @__PURE__ */ new Map();
285
+ constructor(config = {}) {
286
+ this.defaultTransportName = config.default ?? "smtp";
287
+ this.defaultFrom = config.from;
288
+ this.registerBuiltinDrivers();
289
+ if (config.transports) {
290
+ for (const [name, transportConfig] of Object.entries(config.transports)) {
291
+ this.registerTransportFromConfig(name, transportConfig);
292
+ }
293
+ }
294
+ }
295
+ /**
296
+ * Register built-in transport drivers.
297
+ */
298
+ registerBuiltinDrivers() {
299
+ this.registerDriverFactory("smtp", (options) => {
300
+ return new SmtpTransport(options);
301
+ });
302
+ this.registerDriverFactory("resend", (options) => {
303
+ return new ResendTransport(options);
304
+ });
305
+ this.registerDriverFactory("memory", (options) => {
306
+ return new MemoryTransport(options);
307
+ });
308
+ }
309
+ driverFactories = /* @__PURE__ */ new Map();
310
+ /**
311
+ * Register a driver factory.
312
+ */
313
+ registerDriverFactory(driver, factory) {
314
+ this.driverFactories.set(driver, factory);
315
+ }
316
+ /**
317
+ * Register a transport from configuration.
318
+ */
319
+ registerTransportFromConfig(name, config) {
320
+ const { driver, ...options } = config;
321
+ const factory = this.driverFactories.get(driver);
322
+ if (!factory) {
323
+ throw new Error(`Unknown mail driver: ${driver}`);
324
+ }
325
+ this.transportFactories.set(name, () => factory(options));
326
+ }
327
+ /**
328
+ * Get a mail transport by name.
329
+ * Returns the default transport if no name is specified.
330
+ */
331
+ transport(name) {
332
+ const transportName = name ?? this.defaultTransportName;
333
+ const cached = this.resolvedTransports.get(transportName);
334
+ if (cached) {
335
+ return cached;
336
+ }
337
+ const factory = this.transportFactories.get(transportName);
338
+ if (!factory) {
339
+ throw new Error(`Mail transport not found: ${transportName}`);
340
+ }
341
+ const transport = factory();
342
+ this.resolvedTransports.set(transportName, transport);
343
+ return transport;
344
+ }
345
+ /**
346
+ * Register a custom transport.
347
+ */
348
+ registerTransport(name, factory) {
349
+ this.transportFactories.set(name, factory);
350
+ this.resolvedTransports.delete(name);
351
+ }
352
+ /**
353
+ * Check if a transport is registered.
354
+ */
355
+ hasTransport(name) {
356
+ return this.transportFactories.has(name);
357
+ }
358
+ /**
359
+ * Get the default transport name.
360
+ */
361
+ getDefaultTransportName() {
362
+ return this.defaultTransportName;
363
+ }
364
+ /**
365
+ * Get the default from address.
366
+ */
367
+ getDefaultFrom() {
368
+ return this.defaultFrom;
369
+ }
370
+ /**
371
+ * Get all registered transport names.
372
+ */
373
+ getTransportNames() {
374
+ return Array.from(this.transportFactories.keys());
375
+ }
376
+ };
377
+ function createMailManager(config) {
378
+ return new MailManager(config);
379
+ }
380
+
381
+ // src/queue/Job.ts
382
+ import { randomBytes } from "crypto";
383
+
384
+ // src/container/Container.ts
385
+ var globalContainer = null;
386
+ function getContainer() {
387
+ if (!globalContainer) {
388
+ throw new Error("Container not initialized. Call setContainer() first.");
389
+ }
390
+ return globalContainer;
391
+ }
392
+
393
+ // src/queue/Job.ts
394
+ var globalDriver = null;
395
+ function getQueueDriver() {
396
+ return globalDriver;
397
+ }
398
+ function generateJobId() {
399
+ return randomBytes(16).toString("hex");
400
+ }
401
+ var Job = class {
402
+ /**
403
+ * The queue this job should be dispatched to.
404
+ * @default 'default'
405
+ */
406
+ static queue = "default";
407
+ /**
408
+ * Maximum number of times the job should be attempted.
409
+ * @default 3
410
+ */
411
+ static maxAttempts = 3;
412
+ /**
413
+ * Backoff strategy for retries.
414
+ * - 'exponential': 2^attempt * 1000ms (1s, 2s, 4s, 8s, ...)
415
+ * - 'linear': attempt * 1000ms (1s, 2s, 3s, 4s, ...)
416
+ * - number: fixed delay in milliseconds
417
+ * @default 'exponential'
418
+ */
419
+ static backoff = "exponential";
420
+ make(key) {
421
+ return getContainer().make(key);
422
+ }
423
+ /**
424
+ * Dispatch the job to the queue.
425
+ *
426
+ * @param payload - Job payload data
427
+ * @param options - Optional dispatch options
428
+ */
429
+ static async dispatch(payload, options = {}) {
430
+ const driver = globalDriver;
431
+ if (!driver) {
432
+ throw new Error("Queue driver not configured. Call setQueueDriver() first.");
433
+ }
434
+ const jobId = generateJobId();
435
+ const now = /* @__PURE__ */ new Date();
436
+ const delay = options.delay ?? 0;
437
+ const job = {
438
+ id: jobId,
439
+ name: this.name,
440
+ payload,
441
+ queue: options.queue ?? this.queue,
442
+ attempts: 0,
443
+ maxAttempts: options.maxAttempts ?? this.maxAttempts,
444
+ availableAt: new Date(now.getTime() + delay),
445
+ createdAt: now,
446
+ reservedAt: null
447
+ };
448
+ await driver.push(job);
449
+ return jobId;
450
+ }
451
+ /**
452
+ * Dispatch the job after a delay.
453
+ *
454
+ * @param delayMs - Delay in milliseconds
455
+ * @param payload - Job payload data
456
+ * @param options - Optional dispatch options (delay is overridden)
457
+ */
458
+ static async dispatchAfter(delayMs, payload, options = {}) {
459
+ return this.dispatch(payload, { ...options, delay: delayMs });
460
+ }
461
+ /**
462
+ * Calculate the retry delay based on backoff strategy.
463
+ */
464
+ static calculateRetryDelay(attempts) {
465
+ if (typeof this.backoff === "number") {
466
+ return this.backoff;
467
+ }
468
+ if (this.backoff === "linear") {
469
+ return attempts * 1e3;
470
+ }
471
+ return Math.pow(2, attempts) * 1e3;
472
+ }
473
+ };
474
+ var jobRegistry = /* @__PURE__ */ new Map();
475
+ function registerJob(jobClass) {
476
+ jobRegistry.set(jobClass.name, jobClass);
477
+ }
478
+
479
+ // src/mail/Mail.ts
480
+ function parseAddress(input) {
481
+ if (typeof input === "string") {
482
+ const match = input.match(/^(.+)\s*<(.+)>$/);
483
+ if (match) {
484
+ return { name: match[1].trim(), email: match[2].trim() };
485
+ }
486
+ return { email: input };
487
+ }
488
+ return input;
489
+ }
490
+ var Mail = class {
491
+ constructor(manager) {
492
+ this.manager = manager;
493
+ const defaultFrom = manager.getDefaultFrom();
494
+ if (defaultFrom) {
495
+ this.message.from = defaultFrom;
496
+ }
497
+ }
498
+ message = {
499
+ to: [],
500
+ cc: [],
501
+ bcc: [],
502
+ attachments: []
503
+ };
504
+ transportName;
505
+ /**
506
+ * Set the sender address.
507
+ */
508
+ from(address) {
509
+ this.message.from = parseAddress(address);
510
+ return this;
511
+ }
512
+ /**
513
+ * Add a recipient.
514
+ */
515
+ to(address) {
516
+ this.message.to.push(parseAddress(address));
517
+ return this;
518
+ }
519
+ /**
520
+ * Add multiple recipients.
521
+ */
522
+ toMany(addresses) {
523
+ for (const addr of addresses) {
524
+ this.to(addr);
525
+ }
526
+ return this;
527
+ }
528
+ /**
529
+ * Add a CC recipient.
530
+ */
531
+ cc(address) {
532
+ this.message.cc.push(parseAddress(address));
533
+ return this;
534
+ }
535
+ /**
536
+ * Add a BCC recipient.
537
+ */
538
+ bcc(address) {
539
+ this.message.bcc.push(parseAddress(address));
540
+ return this;
541
+ }
542
+ /**
543
+ * Set the reply-to address.
544
+ */
545
+ replyTo(address) {
546
+ this.message.replyTo = parseAddress(address);
547
+ return this;
548
+ }
549
+ /**
550
+ * Set the subject.
551
+ */
552
+ subject(subject) {
553
+ this.message.subject = subject;
554
+ return this;
555
+ }
556
+ /**
557
+ * Set the plain text body.
558
+ */
559
+ text(content) {
560
+ this.message.text = content;
561
+ return this;
562
+ }
563
+ /**
564
+ * Set the HTML body.
565
+ */
566
+ html(content) {
567
+ this.message.html = content;
568
+ return this;
569
+ }
570
+ /**
571
+ * Render a React component as HTML body.
572
+ * Requires @react-email/render to be installed.
573
+ *
574
+ * @param component - React component function
575
+ * @param props - Props to pass to the component
576
+ */
577
+ async template(component, props) {
578
+ try {
579
+ const reactEmailModule = "@react-email/render";
580
+ const reactEmail = await import(
581
+ /* @vite-ignore */
582
+ reactEmailModule
583
+ );
584
+ const html = await reactEmail.render(component(props));
585
+ this.message.html = html;
586
+ } catch (error) {
587
+ throw new Error(
588
+ "Failed to render email template. Make sure @react-email/render is installed."
589
+ );
590
+ }
591
+ return this;
592
+ }
593
+ /**
594
+ * Add an attachment.
595
+ */
596
+ attach(attachment) {
597
+ this.message.attachments.push(attachment);
598
+ return this;
599
+ }
600
+ /**
601
+ * Add a custom header.
602
+ */
603
+ header(key, value) {
604
+ if (!this.message.headers) {
605
+ this.message.headers = {};
606
+ }
607
+ this.message.headers[key] = value;
608
+ return this;
609
+ }
610
+ /**
611
+ * Specify which transport to use.
612
+ */
613
+ via(transport) {
614
+ this.transportName = transport;
615
+ return this;
616
+ }
617
+ /**
618
+ * Build the final message.
619
+ */
620
+ buildMessage() {
621
+ if (!this.message.to || this.message.to.length === 0) {
622
+ throw new Error("Email must have at least one recipient");
623
+ }
624
+ if (!this.message.subject) {
625
+ throw new Error("Email must have a subject");
626
+ }
627
+ if (!this.message.text && !this.message.html) {
628
+ throw new Error("Email must have a text or html body");
629
+ }
630
+ return this.message;
631
+ }
632
+ /**
633
+ * Send the email immediately.
634
+ */
635
+ async send() {
636
+ const message = this.buildMessage();
637
+ const transport = this.manager.transport(this.transportName);
638
+ return transport.send(message);
639
+ }
640
+ /**
641
+ * Queue the email for async sending.
642
+ */
643
+ async queue(queueName = "default") {
644
+ const driver = getQueueDriver();
645
+ if (!driver) {
646
+ throw new Error("Queue driver not configured. Use send() instead or configure a queue driver.");
647
+ }
648
+ const message = this.buildMessage();
649
+ registerJob(SendMailJob);
650
+ return SendMailJob.dispatch(
651
+ {
652
+ message,
653
+ transport: this.transportName ?? this.manager.getDefaultTransportName()
654
+ },
655
+ { queue: queueName }
656
+ );
657
+ }
658
+ };
659
+ var globalMailManager = null;
660
+ function setMailManager(manager) {
661
+ globalMailManager = manager;
662
+ }
663
+ function getMailManager() {
664
+ return globalMailManager;
665
+ }
666
+ var SendMailJob = class extends Job {
667
+ static queue = "default";
668
+ static maxAttempts = 3;
669
+ static backoff = "exponential";
670
+ async handle(payload) {
671
+ const manager = globalMailManager;
672
+ if (!manager) {
673
+ throw new Error("Mail manager not configured for queue jobs. Call setMailManager() first.");
674
+ }
675
+ const transport = manager.transport(payload.transport);
676
+ const result = await transport.send(payload.message);
677
+ if (!result.success) {
678
+ throw new Error(result.error ?? "Failed to send email");
679
+ }
680
+ }
681
+ };
682
+ function mail(manager) {
683
+ return new Mail(manager);
684
+ }
685
+ export {
686
+ Mail,
687
+ MailManager,
688
+ MemoryTransport,
689
+ ResendTransport,
690
+ SmtpTransport,
691
+ createMailManager,
692
+ getMailManager,
693
+ mail,
694
+ setMailManager
695
+ };