@zintrust/core 0.1.24 → 0.1.26

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 (152) hide show
  1. package/package.json +4 -3
  2. package/src/auth/Auth.d.ts.map +1 -0
  3. package/src/boot/Application.d.ts.map +1 -1
  4. package/src/boot/Application.js +8 -0
  5. package/src/boot/bootstrap.js +34 -15
  6. package/src/cache/drivers/RedisDriver.d.ts.map +1 -1
  7. package/src/cache/drivers/RedisDriver.js +10 -5
  8. package/src/cli/CLI.d.ts.map +1 -1
  9. package/src/cli/CLI.js +6 -0
  10. package/src/cli/commands/QueueCommand.d.ts.map +1 -1
  11. package/src/cli/commands/QueueCommand.js +89 -39
  12. package/src/cli/commands/QueueLockCommand.d.ts +7 -0
  13. package/src/cli/commands/QueueLockCommand.d.ts.map +1 -0
  14. package/src/cli/commands/QueueLockCommand.js +138 -0
  15. package/src/cli/commands/StartCommand.d.ts.map +1 -1
  16. package/src/cli/commands/StartCommand.js +15 -3
  17. package/src/cli/commands/TemplatesCommand.js +1 -1
  18. package/src/cli/commands/WorkerCommands.d.ts.map +1 -1
  19. package/src/cli/commands/WorkerCommands.js +46 -22
  20. package/src/cli/scaffolding/ProjectScaffolder.js +2 -2
  21. package/src/cli/scaffolding/RouteGenerator.d.ts.map +1 -1
  22. package/src/cli/scaffolding/RouteGenerator.js +27 -28
  23. package/src/cli/services/VersionChecker.d.ts +53 -0
  24. package/src/cli/services/VersionChecker.d.ts.map +1 -0
  25. package/src/cli/services/VersionChecker.js +180 -0
  26. package/src/cli/workers/QueueWorkRunner.d.ts.map +1 -1
  27. package/src/cli/workers/QueueWorkRunner.js +128 -7
  28. package/src/common/ExternalServiceUtils.d.ts +2 -2
  29. package/src/config/app.d.ts +4 -0
  30. package/src/config/app.d.ts.map +1 -1
  31. package/src/config/app.js +9 -0
  32. package/src/config/constants.d.ts +140 -10
  33. package/src/config/constants.d.ts.map +1 -1
  34. package/src/config/constants.js +86 -5
  35. package/src/config/index.d.ts +1 -0
  36. package/src/config/index.d.ts.map +1 -1
  37. package/src/config/middleware.d.ts +6 -6
  38. package/src/config/middleware.d.ts.map +1 -1
  39. package/src/config/middleware.js +6 -7
  40. package/src/config/queue.d.ts +4 -0
  41. package/src/config/queue.d.ts.map +1 -1
  42. package/src/config/queue.js +1 -1
  43. package/src/config/redis.d.ts +17 -0
  44. package/src/config/redis.d.ts.map +1 -0
  45. package/src/config/redis.js +54 -0
  46. package/src/config/type.d.ts +3 -0
  47. package/src/config/type.d.ts.map +1 -1
  48. package/src/http/Request.d.ts +10 -1
  49. package/src/http/Request.d.ts.map +1 -1
  50. package/src/http/Request.js +79 -7
  51. package/src/http/error-pages/ErrorPageRenderer.d.ts.map +1 -1
  52. package/src/http/error-pages/ErrorPageRenderer.js +4 -3
  53. package/src/index.d.ts +14 -11
  54. package/src/index.d.ts.map +1 -1
  55. package/src/index.js +18 -11
  56. package/src/lang/lang.d.ts +23 -0
  57. package/src/lang/lang.d.ts.map +1 -0
  58. package/src/lang/lang.js +22 -0
  59. package/src/middleware/ErrorHandlerMiddleware.d.ts.map +1 -1
  60. package/src/middleware/ErrorHandlerMiddleware.js +9 -1
  61. package/src/migrations/schema/SchemaCompiler.js +1 -1
  62. package/src/migrations/schema/types.d.ts +1 -1
  63. package/src/migrations/schema/types.d.ts.map +1 -1
  64. package/src/node.d.ts +1 -1
  65. package/src/node.d.ts.map +1 -1
  66. package/src/node.js +1 -1
  67. package/src/orm/Database.d.ts +1 -1
  68. package/src/orm/Database.d.ts.map +1 -1
  69. package/src/orm/Database.js +22 -3
  70. package/src/performance/Optimizer.js +1 -1
  71. package/src/routing/Router.d.ts +6 -2
  72. package/src/routing/Router.d.ts.map +1 -1
  73. package/src/routing/Router.js +19 -4
  74. package/src/runtime/PluginManager.js +1 -1
  75. package/src/runtime/PluginRegistry.js +2 -2
  76. package/src/start.d.ts.map +1 -1
  77. package/src/start.js +8 -7
  78. package/src/templates/TemplateRegistry.js +2 -2
  79. package/src/templates/TemplateRegistry.ts +2 -2
  80. package/src/templates/feature/Queue.ts.tpl +114 -0
  81. package/src/templates/project/basic/app/Controllers/UserController.ts.tpl +22 -0
  82. package/src/templates/project/basic/config/queue.ts.tpl +19 -0
  83. package/src/templates/project/basic/package.json.tpl +2 -1
  84. package/src/templates/project/basic/src/index.ts.tpl +0 -3
  85. package/src/tools/broadcast/drivers/Redis.d.ts.map +1 -1
  86. package/src/tools/broadcast/drivers/Redis.js +8 -56
  87. package/src/tools/mail/Mail.d.ts +1 -29
  88. package/src/tools/mail/Mail.d.ts.map +1 -1
  89. package/src/tools/mail/Mail.js +1 -111
  90. package/src/tools/mail/drivers/SendGrid.d.ts.map +1 -1
  91. package/src/tools/mail/drivers/SendGrid.js +4 -3
  92. package/src/tools/mail/drivers/Smtp.d.ts.map +1 -1
  93. package/src/tools/mail/drivers/Smtp.js +32 -10
  94. package/src/tools/mail/index.d.ts +40 -0
  95. package/src/tools/mail/index.d.ts.map +1 -0
  96. package/src/tools/mail/index.js +129 -0
  97. package/src/tools/mail/template-loader.d.ts +10 -0
  98. package/src/tools/mail/template-loader.d.ts.map +1 -0
  99. package/src/tools/mail/template-loader.js +101 -0
  100. package/src/tools/mail/template-utils.d.ts +10 -0
  101. package/src/tools/mail/template-utils.d.ts.map +1 -0
  102. package/src/tools/mail/template-utils.js +16 -0
  103. package/src/tools/mail/templates/index.d.ts +30 -0
  104. package/src/tools/mail/templates/index.d.ts.map +1 -1
  105. package/src/tools/mail/templates/index.js +69 -0
  106. package/src/tools/queue/AdvancedQueue.d.ts +19 -0
  107. package/src/tools/queue/AdvancedQueue.d.ts.map +1 -0
  108. package/src/tools/queue/AdvancedQueue.js +352 -0
  109. package/src/tools/queue/DeduplicationBuilder.d.ts +20 -0
  110. package/src/tools/queue/DeduplicationBuilder.d.ts.map +1 -0
  111. package/src/tools/queue/DeduplicationBuilder.js +77 -0
  112. package/src/tools/queue/LockProvider.d.ts +22 -0
  113. package/src/tools/queue/LockProvider.d.ts.map +1 -0
  114. package/src/tools/queue/LockProvider.js +282 -0
  115. package/src/tools/queue/Queue.d.ts.map +1 -1
  116. package/src/tools/queue/Queue.js +2 -1
  117. package/src/tools/queue/QueueExtensions.d.ts +46 -0
  118. package/src/tools/queue/QueueExtensions.d.ts.map +1 -0
  119. package/src/tools/queue/QueueExtensions.js +129 -0
  120. package/src/tools/queue/QueueRuntimeRegistration.d.ts.map +1 -1
  121. package/src/tools/queue/QueueRuntimeRegistration.js +2 -2
  122. package/src/tools/queue/drivers/Database.d.ts +23 -0
  123. package/src/tools/queue/drivers/Database.d.ts.map +1 -0
  124. package/src/tools/queue/drivers/Database.js +123 -0
  125. package/src/tools/queue/drivers/Redis.d.ts.map +1 -1
  126. package/src/tools/queue/drivers/Redis.js +11 -82
  127. package/src/tools/queue/index.d.ts +9 -0
  128. package/src/tools/queue/index.d.ts.map +1 -0
  129. package/src/tools/queue/index.js +7 -0
  130. package/src/tools/redis/RedisKeyManager.d.ts +64 -0
  131. package/src/tools/redis/RedisKeyManager.d.ts.map +1 -0
  132. package/src/tools/redis/RedisKeyManager.js +124 -0
  133. package/src/types/Queue.d.ts +62 -0
  134. package/src/types/Queue.d.ts.map +1 -0
  135. package/src/types/Queue.js +5 -0
  136. package/src/features/Auth.d.ts.map +0 -1
  137. package/src/features/Queue.d.ts +0 -21
  138. package/src/features/Queue.d.ts.map +0 -1
  139. package/src/features/Queue.js +0 -33
  140. package/src/templates/features/Queue.ts.tpl +0 -47
  141. package/src/tools/mail/templates/markdown/index.d.ts +0 -17
  142. package/src/tools/mail/templates/markdown/index.d.ts.map +0 -1
  143. package/src/tools/mail/templates/markdown/index.js +0 -49
  144. package/src/tools/mail/templates/markdown/registry.d.ts +0 -15
  145. package/src/tools/mail/templates/markdown/registry.d.ts.map +0 -1
  146. package/src/tools/mail/templates/markdown/registry.js +0 -34
  147. package/src/tools/mail/templates/markdown/validator.d.ts +0 -16
  148. package/src/tools/mail/templates/markdown/validator.d.ts.map +0 -1
  149. package/src/tools/mail/templates/markdown/validator.js +0 -24
  150. /package/src/{features → auth}/Auth.d.ts +0 -0
  151. /package/src/{features → auth}/Auth.js +0 -0
  152. /package/src/templates/{features → auth}/Auth.ts.tpl +0 -0
@@ -1,30 +1,2 @@
1
- import { type AttachmentInput } from './attachments';
2
- export type SendMailInput = {
3
- to: string | string[];
4
- subject: string;
5
- text: string;
6
- html?: string;
7
- from?: {
8
- address?: string;
9
- name?: string;
10
- };
11
- attachments?: AttachmentInput[];
12
- };
13
- export type SendMailResult = {
14
- ok: boolean;
15
- driver: 'sendgrid' | 'disabled' | 'smtp' | 'ses' | 'mailgun' | 'nodemailer';
16
- messageId?: string;
17
- };
18
- export declare const Mail: Readonly<{
19
- /**
20
- * Select a named mailer (key from mailConfig.drivers).
21
- *
22
- * Example: `Mail.mailer('transactional').send(...)`
23
- */
24
- mailer(name: string): Readonly<{
25
- send: (input: SendMailInput) => Promise<SendMailResult>;
26
- }>;
27
- send(input: SendMailInput): Promise<SendMailResult>;
28
- }>;
29
- export default Mail;
1
+ export { default, Mail } from './index';
30
2
  //# sourceMappingURL=Mail.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Mail.d.ts","sourceRoot":"","sources":["../../../../src/tools/mail/Mail.ts"],"names":[],"mappings":"AAMA,OAAO,EAAsB,KAAK,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAI7E,MAAM,MAAM,aAAa,GAAG;IAC1B,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE;QACL,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;IACF,WAAW,CAAC,EAAE,eAAe,EAAE,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,UAAU,GAAG,UAAU,GAAG,MAAM,GAAG,KAAK,GAAG,SAAS,GAAG,YAAY,CAAC;IAC5E,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAoJF,eAAO,MAAM,IAAI;IACf;;;;OAIG;iBACU,MAAM;cAhCb,CAAC,KAAK,EAAE,aAAa,KAAK,OAAO,CAAC,cAAc,CAAC;;gBAoCrC,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC;EAGzD,CAAC;AAEH,eAAe,IAAI,CAAC"}
1
+ {"version":3,"file":"Mail.d.ts","sourceRoot":"","sources":["../../../../src/tools/mail/Mail.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC"}
@@ -1,111 +1 @@
1
- import { mailConfig } from '../../config/mail.js';
2
- import { ErrorFactory } from '../../exceptions/ZintrustError.js';
3
- import { SesDriver } from './drivers/Ses.js';
4
- import { resolveAttachments } from './attachments.js';
5
- import { MailDriverRegistry } from './MailDriverRegistry.js';
6
- import { Storage } from '../storage/index.js';
7
- const resolveFrom = (input) => {
8
- const address = input?.address ?? mailConfig.from.address;
9
- const name = input?.name ?? mailConfig.from.name;
10
- if (address.trim() === '') {
11
- const err = ErrorFactory.createConfigError('Mail: missing from address (set MAIL_FROM_ADDRESS or pass from.address)');
12
- throw err;
13
- }
14
- return { email: address, name: name.trim() === '' ? undefined : name };
15
- };
16
- function assertStorageDiskLike(value) {
17
- if (typeof value !== 'object' || value === null) {
18
- const err = ErrorFactory.createConfigError('Storage disk is invalid (expected object)');
19
- throw err;
20
- }
21
- const v = value;
22
- const driver = v['driver'];
23
- if (typeof driver !== 'object' || driver === null) {
24
- const err = ErrorFactory.createConfigError('Storage disk driver is invalid (expected object)');
25
- throw err;
26
- }
27
- const d = driver;
28
- if (typeof d['get'] !== 'function') {
29
- const err = ErrorFactory.createConfigError('Storage disk driver is missing get()');
30
- throw err;
31
- }
32
- if (typeof d['exists'] !== 'function') {
33
- const err = ErrorFactory.createConfigError('Storage disk driver is missing exists()');
34
- throw err;
35
- }
36
- }
37
- const getDiskSafe = (disk) => {
38
- const diskValue = Storage.getDisk(disk);
39
- assertStorageDiskLike(diskValue);
40
- return diskValue;
41
- };
42
- const createStorageWrapper = () => ({
43
- async get(disk, path) {
44
- const d = getDiskSafe(disk);
45
- const result = await Promise.resolve(d.driver.get(d.config, path));
46
- return result;
47
- },
48
- async exists(disk, path) {
49
- const d = getDiskSafe(disk);
50
- const result = await Promise.resolve(d.driver.exists(d.config, path));
51
- return Boolean(result);
52
- },
53
- });
54
- const sendWithDriver = async (driver, message) => {
55
- if (driver.driver === 'ses') {
56
- const result = await SesDriver.send({ region: driver.region }, message);
57
- return { ok: result.ok, driver: 'ses', messageId: result.messageId };
58
- }
59
- // Drivers resolve via MailDriverRegistry (external packages)
60
- const external = MailDriverRegistry.get(driver.driver);
61
- if (external !== undefined) {
62
- const result = await external(driver, message);
63
- return {
64
- ok: Boolean(result?.ok),
65
- driver: driver.driver,
66
- messageId: typeof result?.messageId === 'string' ? result.messageId : undefined,
67
- };
68
- }
69
- if (driver.driver === 'sendgrid' || driver.driver === 'mailgun' || driver.driver === 'smtp') {
70
- throw ErrorFactory.createConfigError(`Mail driver not registered: ${driver.driver} (run \`zin add mail:${driver.driver}\` / \`npm i @zintrust/mail-${driver.driver}\`)`);
71
- }
72
- // Config exists for future drivers, but implementations are intentionally CLI/runtime-safe and added incrementally.
73
- {
74
- const err = ErrorFactory.createConfigError(`Mail driver not implemented: ${mailConfig.default}`);
75
- throw err;
76
- }
77
- };
78
- const createMailer = (name) => Object.freeze({
79
- async send(input) {
80
- const driver = mailConfig.getDriver(name);
81
- if (driver.driver === 'disabled') {
82
- const err = ErrorFactory.createConfigError('Mail driver is disabled (set MAIL_DRIVER)');
83
- throw err;
84
- }
85
- const from = resolveFrom(input.from);
86
- const storage = createStorageWrapper();
87
- const attachments = await resolveAttachments(input.attachments, { storage });
88
- return sendWithDriver(driver, {
89
- to: input.to,
90
- from,
91
- subject: input.subject,
92
- text: input.text,
93
- html: input.html,
94
- attachments,
95
- });
96
- },
97
- });
98
- export const Mail = Object.freeze({
99
- /**
100
- * Select a named mailer (key from mailConfig.drivers).
101
- *
102
- * Example: `Mail.mailer('transactional').send(...)`
103
- */
104
- mailer(name) {
105
- return createMailer(name);
106
- },
107
- async send(input) {
108
- return createMailer().send(input);
109
- },
110
- });
111
- export default Mail;
1
+ export { default, Mail } from './index.js';
@@ -1 +1 @@
1
- {"version":3,"file":"SendGrid.d.ts","sourceRoot":"","sources":["../../../../../src/tools/mail/drivers/SendGrid.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnE,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACtB,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,cAAc,EAAE,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,EAAE,EAAE,OAAO,CAAC;IACZ,QAAQ,EAAE,UAAU,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAIF,eAAO,MAAM,cAAc;iBACN,cAAc,WAAW,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;EAoE7E,CAAC;AAEH,eAAe,cAAc,CAAC"}
1
+ {"version":3,"file":"SendGrid.d.ts","sourceRoot":"","sources":["../../../../../src/tools/mail/drivers/SendGrid.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnE,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACtB,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,cAAc,EAAE,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,EAAE,EAAE,OAAO,CAAC;IACZ,QAAQ,EAAE,UAAU,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAIF,eAAO,MAAM,cAAc;iBACN,cAAc,WAAW,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;EAoE7E,CAAC;AAEH,eAAe,cAAc,CAAC"}
@@ -1,3 +1,4 @@
1
+ import { MIME_TYPES } from '../../../config/constants.js';
1
2
  import { ErrorFactory } from '../../../exceptions/ZintrustError.js';
2
3
  const normalizeRecipients = (to) => (Array.isArray(to) ? to : [to]);
3
4
  export const SendGridDriver = Object.freeze({
@@ -14,10 +15,10 @@ export const SendGridDriver = Object.freeze({
14
15
  },
15
16
  ];
16
17
  const content = [
17
- { type: 'text/plain', value: message.text },
18
+ { type: MIME_TYPES.TEXT, value: message.text },
18
19
  ];
19
20
  if (typeof message.html === 'string' && message.html !== '') {
20
- content.push({ type: 'text/html', value: message.html });
21
+ content.push({ type: MIME_TYPES.HTML, value: message.html });
21
22
  }
22
23
  const body = {
23
24
  personalizations,
@@ -38,7 +39,7 @@ export const SendGridDriver = Object.freeze({
38
39
  method: 'POST',
39
40
  headers: {
40
41
  Authorization: `Bearer ${config.apiKey}`,
41
- 'content-type': 'application/json',
42
+ 'content-type': MIME_TYPES.JSON,
42
43
  },
43
44
  body: JSON.stringify(body),
44
45
  });
@@ -1 +1 @@
1
- {"version":3,"file":"Smtp.d.ts","sourceRoot":"","sources":["../../../../../src/tools/mail/drivers/Smtp.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,GAAG,UAAU,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnE,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACtB,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,cAAc,EAAE,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,EAAE,EAAE,OAAO,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AA0XF,eAAO,MAAM,UAAU;IACrB;;;;OAIG;iBACgB,UAAU,WAAW,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;EAgDzE,CAAC;AAEH,eAAe,UAAU,CAAC"}
1
+ {"version":3,"file":"Smtp.d.ts","sourceRoot":"","sources":["../../../../../src/tools/mail/drivers/Smtp.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,GAAG,UAAU,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnE,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACtB,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,cAAc,EAAE,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,EAAE,EAAE,OAAO,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AA+YF,eAAO,MAAM,UAAU;IACrB;;;;OAIG;iBACgB,UAAU,WAAW,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;EAgDzE,CAAC;AAEH,eAAe,UAAU,CAAC"}
@@ -78,7 +78,7 @@ const createLineReader = (socket) => {
78
78
  return undefined;
79
79
  const line = buffer.slice(0, idx + 1);
80
80
  buffer = buffer.slice(idx + 1);
81
- return line.replaceAll(/\r?\n$/, '');
81
+ return line.replace(/\r?\n$/, '');
82
82
  };
83
83
  const readLine = async () => {
84
84
  const immediate = tryReadLineFromBuffer();
@@ -159,15 +159,37 @@ const doAuthLoginIfNeeded = async (socket, reader, config) => {
159
159
  if (username.trim() === '' || password.trim() === '') {
160
160
  throw ErrorFactory.createConfigError('SMTP: both MAIL_USERNAME and MAIL_PASSWORD are required');
161
161
  }
162
- await writeLine(socket, 'AUTH LOGIN');
163
- const auth1 = await reader.readResponse();
164
- assertCode(auth1, 334, 'AUTH LOGIN');
165
- await writeLine(socket, toBase64(username));
166
- const auth2 = await reader.readResponse();
167
- assertCode(auth2, 334, 'AUTH username');
168
- await writeLine(socket, toBase64(password));
169
- const auth3 = await reader.readResponse();
170
- assertCode(auth3, 235, 'AUTH password');
162
+ // Try AUTH PLAIN first (more widely supported)
163
+ try {
164
+ // AUTH PLAIN format: base64("\0username\0password")
165
+ const authPlainString = `\0${username}\0${password}`;
166
+ const authPlainEncoded = toBase64(authPlainString);
167
+ await writeLine(socket, `AUTH PLAIN ${authPlainEncoded}`);
168
+ const authPlain = await reader.readResponse();
169
+ assertCode(authPlain, 235, 'AUTH PLAIN');
170
+ return; // Success!
171
+ }
172
+ catch (plainError) {
173
+ // AUTH PLAIN failed, try AUTH LOGIN as fallback
174
+ try {
175
+ await writeLine(socket, 'AUTH LOGIN');
176
+ const auth1 = await reader.readResponse();
177
+ assertCode(auth1, 334, 'AUTH LOGIN');
178
+ await writeLine(socket, toBase64(username));
179
+ const auth2 = await reader.readResponse();
180
+ assertCode(auth2, 334, 'AUTH username');
181
+ await writeLine(socket, toBase64(password));
182
+ const auth3 = await reader.readResponse();
183
+ assertCode(auth3, 235, 'AUTH password');
184
+ }
185
+ catch (loginError) {
186
+ // Both methods failed, throw the original error
187
+ throw ErrorFactory.createConnectionError('SMTP authentication failed', {
188
+ error: plainError,
189
+ loginError,
190
+ });
191
+ }
192
+ }
171
193
  };
172
194
  const doMailFrom = async (socket, reader, fromEmail) => {
173
195
  await writeLine(socket, `MAIL FROM:<${fromEmail}>`);
@@ -0,0 +1,40 @@
1
+ import { type AttachmentInput } from './attachments';
2
+ export type SendMailInput = {
3
+ to: string | string[];
4
+ subject: string;
5
+ text: string;
6
+ html?: string;
7
+ from?: {
8
+ address?: string;
9
+ name?: string;
10
+ };
11
+ attachments?: AttachmentInput[];
12
+ };
13
+ export type SendMailResult = {
14
+ ok: boolean;
15
+ driver: 'sendgrid' | 'disabled' | 'smtp' | 'ses' | 'mailgun' | 'nodemailer';
16
+ messageId?: string;
17
+ };
18
+ export interface RenderMailInput {
19
+ template: string;
20
+ variables?: Record<string, unknown>;
21
+ }
22
+ export declare const Mail: Readonly<{
23
+ /**
24
+ * Render a template with variables and return HTML (preview only).
25
+ */
26
+ render(input: RenderMailInput): Promise<string>;
27
+ /** Alias of render */
28
+ view(input: RenderMailInput): Promise<string>;
29
+ /**
30
+ * Select a named mailer (key from mailConfig.drivers).
31
+ *
32
+ * Example: `Mail.mailer('transactional').send(...)`
33
+ */
34
+ mailer(name: string): Readonly<{
35
+ send: (input: SendMailInput) => Promise<SendMailResult>;
36
+ }>;
37
+ send(input: SendMailInput): Promise<SendMailResult>;
38
+ }>;
39
+ export default Mail;
40
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/tools/mail/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAsB,KAAK,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAI7E,MAAM,MAAM,aAAa,GAAG;IAC1B,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE;QACL,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;IACF,WAAW,CAAC,EAAE,eAAe,EAAE,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,UAAU,GAAG,UAAU,GAAG,MAAM,GAAG,KAAK,GAAG,SAAS,GAAG,YAAY,CAAC;IAC5E,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAoJF,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC;AAcD,eAAO,MAAM,IAAI;IACf;;OAEG;kBACiB,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC;IAIrD,sBAAsB;gBACJ,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC;IAGnD;;;;OAIG;iBACU,MAAM;cA5Db,CAAC,KAAK,EAAE,aAAa,KAAK,OAAO,CAAC,cAAc,CAAC;;gBAgErC,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC;EAGzD,CAAC;AAEH,eAAe,IAAI,CAAC"}
@@ -0,0 +1,129 @@
1
+ import { mailConfig } from '../../config/mail.js';
2
+ import { ErrorFactory } from '../../exceptions/ZintrustError.js';
3
+ import { SesDriver } from './drivers/Ses.js';
4
+ import { resolveAttachments } from './attachments.js';
5
+ import { MailDriverRegistry } from './MailDriverRegistry.js';
6
+ import { Storage } from '../storage/index.js';
7
+ const resolveFrom = (input) => {
8
+ const address = input?.address ?? mailConfig.from.address;
9
+ const name = input?.name ?? mailConfig.from.name;
10
+ if (address.trim() === '') {
11
+ const err = ErrorFactory.createConfigError('Mail: missing from address (set MAIL_FROM_ADDRESS or pass from.address)');
12
+ throw err;
13
+ }
14
+ return { email: address, name: name.trim() === '' ? undefined : name };
15
+ };
16
+ function assertStorageDiskLike(value) {
17
+ if (typeof value !== 'object' || value === null) {
18
+ const err = ErrorFactory.createConfigError('Storage disk is invalid (expected object)');
19
+ throw err;
20
+ }
21
+ const v = value;
22
+ const driver = v['driver'];
23
+ if (typeof driver !== 'object' || driver === null) {
24
+ const err = ErrorFactory.createConfigError('Storage disk driver is invalid (expected object)');
25
+ throw err;
26
+ }
27
+ const d = driver;
28
+ if (typeof d['get'] !== 'function') {
29
+ const err = ErrorFactory.createConfigError('Storage disk driver is missing get()');
30
+ throw err;
31
+ }
32
+ if (typeof d['exists'] !== 'function') {
33
+ const err = ErrorFactory.createConfigError('Storage disk driver is missing exists()');
34
+ throw err;
35
+ }
36
+ }
37
+ const getDiskSafe = (disk) => {
38
+ const diskValue = Storage.getDisk(disk);
39
+ assertStorageDiskLike(diskValue);
40
+ return diskValue;
41
+ };
42
+ const createStorageWrapper = () => ({
43
+ async get(disk, path) {
44
+ const d = getDiskSafe(disk);
45
+ const result = await Promise.resolve(d.driver.get(d.config, path));
46
+ return result;
47
+ },
48
+ async exists(disk, path) {
49
+ const d = getDiskSafe(disk);
50
+ const result = await Promise.resolve(d.driver.exists(d.config, path));
51
+ return Boolean(result);
52
+ },
53
+ });
54
+ const sendWithDriver = async (driver, message) => {
55
+ if (driver.driver === 'ses') {
56
+ const result = await SesDriver.send({ region: driver.region }, message);
57
+ return { ok: result.ok, driver: 'ses', messageId: result.messageId };
58
+ }
59
+ // Drivers resolve via MailDriverRegistry (external packages)
60
+ const external = MailDriverRegistry.get(driver.driver);
61
+ if (external !== undefined) {
62
+ const result = await external(driver, message);
63
+ return {
64
+ ok: Boolean(result?.ok),
65
+ driver: driver.driver,
66
+ messageId: typeof result?.messageId === 'string' ? result.messageId : undefined,
67
+ };
68
+ }
69
+ if (driver.driver === 'sendgrid' || driver.driver === 'mailgun' || driver.driver === 'smtp') {
70
+ throw ErrorFactory.createConfigError(`Mail driver not registered: ${driver.driver} (run \`zin add mail:${driver.driver}\` / \`npm i @zintrust/mail-${driver.driver}\`)`);
71
+ }
72
+ // Config exists for future drivers, but implementations are intentionally CLI/runtime-safe and added incrementally.
73
+ {
74
+ const err = ErrorFactory.createConfigError(`Mail driver not implemented: ${mailConfig.default}`);
75
+ throw err;
76
+ }
77
+ };
78
+ const createMailer = (name) => Object.freeze({
79
+ async send(input) {
80
+ const driver = mailConfig.getDriver(name);
81
+ if (driver.driver === 'disabled') {
82
+ const err = ErrorFactory.createConfigError('Mail driver is disabled (set MAIL_DRIVER)');
83
+ throw err;
84
+ }
85
+ const from = resolveFrom(input.from);
86
+ const storage = createStorageWrapper();
87
+ const attachments = await resolveAttachments(input.attachments, { storage });
88
+ return sendWithDriver(driver, {
89
+ to: input.to,
90
+ from,
91
+ subject: input.subject,
92
+ text: input.text,
93
+ html: input.html,
94
+ attachments,
95
+ });
96
+ },
97
+ });
98
+ async function renderTemplateToHtml(input) {
99
+ const { template, variables } = input;
100
+ // Import lazily to avoid circular deps
101
+ const { loadTemplate } = await import('./template-loader.js');
102
+ // template-loader expects full filename
103
+ const fileName = template.endsWith('.html') ? template : `${template}.html`;
104
+ return loadTemplate(fileName, (variables ?? {}));
105
+ }
106
+ export const Mail = Object.freeze({
107
+ /**
108
+ * Render a template with variables and return HTML (preview only).
109
+ */
110
+ async render(input) {
111
+ return renderTemplateToHtml(input);
112
+ },
113
+ /** Alias of render */
114
+ async view(input) {
115
+ return renderTemplateToHtml(input);
116
+ },
117
+ /**
118
+ * Select a named mailer (key from mailConfig.drivers).
119
+ *
120
+ * Example: `Mail.mailer('transactional').send(...)`
121
+ */
122
+ mailer(name) {
123
+ return createMailer(name);
124
+ },
125
+ async send(input) {
126
+ return createMailer().send(input);
127
+ },
128
+ });
129
+ export default Mail;
@@ -0,0 +1,10 @@
1
+ import type { TemplateVariables } from './template-utils';
2
+ /**
3
+ * Load and render email template with variable substitution
4
+ */
5
+ export declare function loadTemplate(templateName: string, variables?: TemplateVariables): Promise<string>;
6
+ /**
7
+ * Get list of available templates
8
+ */
9
+ export declare function getAvailableTemplates(): string[];
10
+ //# sourceMappingURL=template-loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-loader.d.ts","sourceRoot":"","sources":["../../../../src/tools/mail/template-loader.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAG9D;;GAEG;AACH,wBAAsB,YAAY,CAChC,YAAY,EAAE,MAAM,EACpB,SAAS,GAAE,iBAAsB,GAChC,OAAO,CAAC,MAAM,CAAC,CA6CjB;AAuDD;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,EAAE,CAShD"}
@@ -0,0 +1,101 @@
1
+ import { ErrorFactory } from '../../exceptions/ZintrustError.js';
2
+ import { readFile } from '../../node-singletons/fs.js';
3
+ import { dirname, join } from '../../node-singletons/path.js';
4
+ import { fileURLToPath } from '../../node-singletons/url.js';
5
+ import { Env } from '../../config/env.js';
6
+ import { interpolate } from './template-utils.js';
7
+ /**
8
+ * Load and render email template with variable substitution
9
+ */
10
+ export async function loadTemplate(templateName, variables = {}) {
11
+ try {
12
+ const baseDir = dirname(fileURLToPath(import.meta.url));
13
+ const isPath = templateName.includes('/') || templateName.endsWith('.html');
14
+ let templatePath;
15
+ if (isPath) {
16
+ if (templateName.startsWith('/')) {
17
+ templatePath = templateName;
18
+ }
19
+ else {
20
+ templatePath = join(process.cwd(), templateName);
21
+ }
22
+ }
23
+ else {
24
+ templatePath = join(baseDir, 'templates', `${templateName}.html`);
25
+ }
26
+ let template;
27
+ try {
28
+ template = await readFile(templatePath, 'utf-8');
29
+ }
30
+ catch {
31
+ // Fallback to built-in directory if the supplied name looked like a file but wasn't found
32
+ const fallbackPath = join(baseDir, 'templates', templateName.endsWith('.html') ? templateName : `${templateName}.html`);
33
+ template = await readFile(fallbackPath, 'utf-8');
34
+ }
35
+ // Replace variables using shared interpolate util
36
+ const mergedVars = {
37
+ year: new Date().getFullYear().toString(),
38
+ APP_NAME: Env.APP_NAME ?? 'ZinTrust',
39
+ ...variables,
40
+ };
41
+ let rendered = interpolate(template, mergedVars);
42
+ // Handle conditional blocks {{#if_condition}}...{{/if_condition}}
43
+ rendered = renderConditionals(rendered, variables);
44
+ // Handle loops {{#each_array}}...{{/each_array}}
45
+ rendered = renderLoops(rendered, variables);
46
+ return rendered;
47
+ }
48
+ catch (error) {
49
+ throw ErrorFactory.createConfigError(`Failed to load template ${templateName}: ${error}`);
50
+ }
51
+ }
52
+ /**
53
+ * Render conditional blocks {{#if_condition}}...{{/if_condition}}
54
+ */
55
+ function renderConditionals(template, variables) {
56
+ const conditionalRegex = /{{#if_(\w+)}}(.+?){{\/if_\1}}/gs;
57
+ return template.replaceAll(conditionalRegex, (_fullMatch, condition, content) => {
58
+ const value = variables[condition];
59
+ if (value === true || value === 'true') {
60
+ return content;
61
+ }
62
+ return '';
63
+ });
64
+ }
65
+ /**
66
+ * Render loop blocks {{#each_array}}...{{/each_array}}
67
+ */
68
+ function renderLoops(template, variables) {
69
+ const loopRegex = /{{#each_(\w+)}}(.+?){{\/each_\1}}/gs;
70
+ return template.replaceAll(loopRegex, (_fullMatch, arrayName, content) => {
71
+ const array = variables[arrayName];
72
+ if (!Array.isArray(array)) {
73
+ return '';
74
+ }
75
+ return array
76
+ .map((item) => {
77
+ let rendered = content;
78
+ if (typeof item === 'object' && item !== null) {
79
+ for (const [key, value] of Object.entries(item)) {
80
+ const regex = new RegExp(`{{${key}}}`, 'g');
81
+ rendered = rendered.replaceAll(regex, String(value ?? ''));
82
+ }
83
+ }
84
+ return rendered;
85
+ })
86
+ .join('');
87
+ });
88
+ }
89
+ /**
90
+ * Get list of available templates
91
+ */
92
+ export function getAvailableTemplates() {
93
+ return [
94
+ 'welcome.html',
95
+ 'password-reset.html',
96
+ 'job-completed.html',
97
+ 'worker-alert.html',
98
+ 'performance-report.html',
99
+ 'general.html',
100
+ ];
101
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Template utilities shared by mail modules.
3
+ */
4
+ export type TemplateVariables = Record<string, unknown>;
5
+ /**
6
+ * Simple handlebars‐style interpolation: replaces all occurrences of
7
+ * `{{ key }}` (whitespace optional) with String(value).
8
+ */
9
+ export declare function interpolate(template: string, data: TemplateVariables): string;
10
+ //# sourceMappingURL=template-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-utils.d.ts","sourceRoot":"","sources":["../../../../src/tools/mail/template-utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAExD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,GAAG,MAAM,CAQ7E"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Template utilities shared by mail modules.
3
+ */
4
+ /**
5
+ * Simple handlebars‐style interpolation: replaces all occurrences of
6
+ * `{{ key }}` (whitespace optional) with String(value).
7
+ */
8
+ export function interpolate(template, data) {
9
+ let out = template;
10
+ for (const [key, value] of Object.entries(data)) {
11
+ const replacement = value === null || value === undefined ? '' : String(value);
12
+ const regex = new RegExp(String.raw `{{\s*${key}\s*}}`, 'g');
13
+ out = out.replace(regex, replacement);
14
+ }
15
+ return out;
16
+ }
@@ -24,4 +24,34 @@ export declare const MailTemplates: Readonly<{
24
24
  }>;
25
25
  }>;
26
26
  }>;
27
+ export interface MarkdownTemplateMetadata {
28
+ subject?: string;
29
+ preheader?: string;
30
+ variables?: string[];
31
+ content: string;
32
+ }
33
+ export interface MarkdownRenderResult {
34
+ html: string;
35
+ meta: {
36
+ subject?: string;
37
+ content: string;
38
+ variables?: string[];
39
+ };
40
+ }
41
+ /**
42
+ * List all available HTML mail templates.
43
+ * Returns template names without the .html extension.
44
+ */
45
+ export declare function listTemplates(): string[];
46
+ /**
47
+ * Load a mail template by name.
48
+ * Note: HTML templates don't have embedded metadata like markdown templates did.
49
+ * This function returns the raw HTML content.
50
+ */
51
+ export declare function loadTemplate(name: string): MarkdownTemplateMetadata;
52
+ /**
53
+ * Render a mail template with variables.
54
+ * Note: This is a compatibility function. For production use, use MailTemplateRenderer instead.
55
+ */
56
+ export declare function renderTemplate(name: string, variables?: Record<string, unknown>): MarkdownRenderResult;
27
57
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/tools/mail/templates/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAW3D,eAAO,MAAM,oBAAoB;6BATD,MAAM,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,MAAM;qBAY3D,YAAY,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,YAAY;EAO3E,CAAC;AAEH,eAAO,MAAM,aAAa;;;;;;;;EASO,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/tools/mail/templates/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAW3D,eAAO,MAAM,oBAAoB;6BATD,MAAM,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,MAAM;qBAY3D,YAAY,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,YAAY;EAO3E,CAAC;AAEH,eAAO,MAAM,aAAa;;;;;;;;EASO,CAAC;AAYlC,MAAM,WAAW,wBAAwB;IACvC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE;QACJ,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;KACtB,CAAC;CACH;AAED;;;GAGG;AACH,wBAAgB,aAAa,IAAI,MAAM,EAAE,CAWxC;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,wBAAwB,CAiBnE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAClC,oBAAoB,CAoBtB"}