@zintrust/core 0.1.12 → 0.1.14

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 (108) hide show
  1. package/package.json +1 -1
  2. package/src/boot/Application.d.ts.map +1 -1
  3. package/src/boot/Application.js +142 -11
  4. package/src/cache/Cache.d.ts +13 -0
  5. package/src/cache/Cache.d.ts.map +1 -1
  6. package/src/cache/Cache.js +48 -6
  7. package/src/cache/CacheRuntimeRegistration.d.ts +11 -0
  8. package/src/cache/CacheRuntimeRegistration.d.ts.map +1 -0
  9. package/src/cache/CacheRuntimeRegistration.js +21 -0
  10. package/src/config/broadcast.d.ts +18 -4
  11. package/src/config/broadcast.d.ts.map +1 -1
  12. package/src/config/broadcast.js +60 -12
  13. package/src/config/cache.d.ts +1 -1
  14. package/src/config/cache.d.ts.map +1 -1
  15. package/src/config/cache.js +19 -8
  16. package/src/config/database.d.ts +1 -1
  17. package/src/config/database.d.ts.map +1 -1
  18. package/src/config/database.js +59 -43
  19. package/src/config/index.d.ts +23 -2
  20. package/src/config/index.d.ts.map +1 -1
  21. package/src/config/index.js +6 -0
  22. package/src/config/mail.d.ts +3 -3
  23. package/src/config/mail.d.ts.map +1 -1
  24. package/src/config/mail.js +24 -9
  25. package/src/config/notification.d.ts +25 -29
  26. package/src/config/notification.d.ts.map +1 -1
  27. package/src/config/notification.js +75 -20
  28. package/src/config/storage.d.ts +8 -0
  29. package/src/config/storage.d.ts.map +1 -1
  30. package/src/config/storage.js +29 -7
  31. package/src/config/type.d.ts +32 -31
  32. package/src/config/type.d.ts.map +1 -1
  33. package/src/index.d.ts +16 -3
  34. package/src/index.d.ts.map +1 -1
  35. package/src/index.js +16 -3
  36. package/src/node.d.ts +6 -4
  37. package/src/node.d.ts.map +1 -1
  38. package/src/node.js +6 -4
  39. package/src/orm/Database.d.ts.map +1 -1
  40. package/src/orm/Database.js +4 -0
  41. package/src/orm/DatabaseRuntimeRegistration.d.ts +17 -0
  42. package/src/orm/DatabaseRuntimeRegistration.d.ts.map +1 -0
  43. package/src/orm/DatabaseRuntimeRegistration.js +55 -0
  44. package/src/orm/Model.d.ts +3 -9
  45. package/src/orm/Model.d.ts.map +1 -1
  46. package/src/orm/Model.js +9 -7
  47. package/src/templates/project/basic/config/broadcast.ts.tpl +79 -11
  48. package/src/templates/project/basic/config/cache.ts.tpl +21 -9
  49. package/src/templates/project/basic/config/database.ts.tpl +67 -50
  50. package/src/templates/project/basic/config/index.ts.tpl +6 -0
  51. package/src/templates/project/basic/config/mail.ts.tpl +24 -11
  52. package/src/templates/project/basic/config/notification.ts.tpl +98 -25
  53. package/src/templates/project/basic/config/storage.ts.tpl +33 -17
  54. package/src/templates/project/basic/config/type.ts.tpl +46 -33
  55. package/src/templates/project/basic/routes/health.ts.tpl +21 -11
  56. package/src/tools/broadcast/Broadcast.d.ts +5 -3
  57. package/src/tools/broadcast/Broadcast.d.ts.map +1 -1
  58. package/src/tools/broadcast/Broadcast.js +48 -24
  59. package/src/tools/broadcast/BroadcastRegistry.d.ts +15 -0
  60. package/src/tools/broadcast/BroadcastRegistry.d.ts.map +1 -0
  61. package/src/tools/broadcast/BroadcastRegistry.js +29 -0
  62. package/src/tools/broadcast/BroadcastRuntimeRegistration.d.ts +11 -0
  63. package/src/tools/broadcast/BroadcastRuntimeRegistration.d.ts.map +1 -0
  64. package/src/tools/broadcast/BroadcastRuntimeRegistration.js +20 -0
  65. package/src/tools/broadcast/index.d.ts +2 -0
  66. package/src/tools/broadcast/index.d.ts.map +1 -1
  67. package/src/tools/broadcast/index.js +2 -0
  68. package/src/tools/mail/Mail.d.ts +8 -0
  69. package/src/tools/mail/Mail.d.ts.map +1 -1
  70. package/src/tools/mail/Mail.js +15 -2
  71. package/src/tools/mail/MailDriverRegistry.d.ts +2 -0
  72. package/src/tools/mail/MailDriverRegistry.d.ts.map +1 -1
  73. package/src/tools/mail/MailDriverRegistry.js +4 -0
  74. package/src/tools/notification/Notification.d.ts +3 -0
  75. package/src/tools/notification/Notification.d.ts.map +1 -1
  76. package/src/tools/notification/Notification.js +3 -0
  77. package/src/tools/notification/NotificationChannelRegistry.d.ts +15 -0
  78. package/src/tools/notification/NotificationChannelRegistry.d.ts.map +1 -0
  79. package/src/tools/notification/NotificationChannelRegistry.js +36 -0
  80. package/src/tools/notification/NotificationRuntimeRegistration.d.ts +13 -0
  81. package/src/tools/notification/NotificationRuntimeRegistration.d.ts.map +1 -0
  82. package/src/tools/notification/NotificationRuntimeRegistration.js +22 -0
  83. package/src/tools/notification/Registry.d.ts.map +1 -1
  84. package/src/tools/notification/Registry.js +4 -0
  85. package/src/tools/notification/Service.d.ts +1 -0
  86. package/src/tools/notification/Service.d.ts.map +1 -1
  87. package/src/tools/notification/Service.js +77 -4
  88. package/src/tools/notification/drivers/SlackNotification.d.ts +8 -0
  89. package/src/tools/notification/drivers/SlackNotification.d.ts.map +1 -0
  90. package/src/tools/notification/drivers/SlackNotification.js +13 -0
  91. package/src/tools/notification/drivers/TwilioNotification.d.ts +8 -0
  92. package/src/tools/notification/drivers/TwilioNotification.d.ts.map +1 -0
  93. package/src/tools/notification/drivers/TwilioNotification.js +13 -0
  94. package/src/tools/queue/Queue.d.ts +1 -0
  95. package/src/tools/queue/Queue.d.ts.map +1 -1
  96. package/src/tools/queue/Queue.js +3 -0
  97. package/src/tools/queue/QueueRuntimeRegistration.d.ts +11 -0
  98. package/src/tools/queue/QueueRuntimeRegistration.d.ts.map +1 -0
  99. package/src/tools/queue/QueueRuntimeRegistration.js +28 -0
  100. package/src/tools/storage/StorageDiskRegistry.d.ts +14 -0
  101. package/src/tools/storage/StorageDiskRegistry.d.ts.map +1 -0
  102. package/src/tools/storage/StorageDiskRegistry.js +36 -0
  103. package/src/tools/storage/StorageRuntimeRegistration.d.ts +10 -0
  104. package/src/tools/storage/StorageRuntimeRegistration.d.ts.map +1 -0
  105. package/src/tools/storage/StorageRuntimeRegistration.js +23 -0
  106. package/src/tools/storage/index.d.ts +1 -0
  107. package/src/tools/storage/index.d.ts.map +1 -1
  108. package/src/tools/storage/index.js +40 -6
@@ -1,5 +1,5 @@
1
- import { Env } from './env';
2
- import type { Middleware as MiddlewareFn } from '../middleware/MiddlewareStack';
1
+ import { Env } from '@config/env';
2
+ import type { Middleware as MiddlewareFn } from '@middleware/MiddlewareStack';
3
3
 
4
4
  export type Environment =
5
5
  | 'development'
@@ -50,15 +50,15 @@ export type GcsStorageDriverConfig = {
50
50
  url: EnvGetValue;
51
51
  };
52
52
 
53
- export type StorageDrivers = {
54
- local: LocalStorageDriverConfig;
55
- s3: S3StorageDriverConfig;
56
- r2: R2StorageDriverConfig;
57
- gcs: GcsStorageDriverConfig;
58
- };
53
+ export type StorageDriverConfig =
54
+ | LocalStorageDriverConfig
55
+ | S3StorageDriverConfig
56
+ | R2StorageDriverConfig
57
+ | GcsStorageDriverConfig;
58
+
59
+ export type StorageDrivers = Record<string, StorageDriverConfig>;
59
60
 
60
61
  export type StorageDriverName = keyof StorageDrivers;
61
- export type StorageDriverConfig = StorageDrivers[StorageDriverName];
62
62
 
63
63
  export type StorageConfigRuntime = {
64
64
  readonly default: string;
@@ -194,6 +194,13 @@ export type KnownNotificationDriverConfig =
194
194
  | TwilioNotificationDriverConfig
195
195
  | SlackNotificationDriverConfig;
196
196
 
197
+ export type NotificationDrivers = Record<string, KnownNotificationDriverConfig>;
198
+
199
+ export type NotificationConfigInput = {
200
+ default: string;
201
+ drivers: NotificationDrivers;
202
+ };
203
+
197
204
  export type NotificationProviders = {
198
205
  console: ConsoleNotificationDriverConfig;
199
206
  termii: TermiiNotificationDriverConfig;
@@ -256,17 +263,16 @@ export type MailDriverConfig =
256
263
  | NodemailerMailDriverConfig
257
264
  | SesMailDriverConfig;
258
265
 
259
- export type MailDrivers = {
260
- disabled: DisabledMailDriverConfig;
261
- sendgrid: SendGridMailDriverConfig;
262
- mailgun: MailgunMailDriverConfig;
263
- smtp: SmtpMailDriverConfig;
264
- nodemailer: NodemailerMailDriverConfig;
265
- ses: SesMailDriverConfig;
266
- };
266
+ export type MailDrivers = Record<string, MailDriverConfig>;
267
267
 
268
268
  export type MailConfigInput = {
269
- default: MailDriverName;
269
+ /**
270
+ * Default mailer key name.
271
+ *
272
+ * This is intentionally a string to support named mailers (e.g. 'transactional', 'marketing').
273
+ * The underlying driver is selected by the `driver` field within each mailer config.
274
+ */
275
+ default: string;
270
276
  from: {
271
277
  address: string;
272
278
  name: string;
@@ -317,17 +323,23 @@ export type MysqlConnectionConfig = {
317
323
  };
318
324
  };
319
325
 
320
- export type DatabaseConnections = {
321
- sqlite: SqliteConnectionConfig;
322
- postgresql: PostgresqlConnectionConfig;
323
- mysql: MysqlConnectionConfig;
324
- };
326
+ export type DatabaseConnectionConfig =
327
+ | SqliteConnectionConfig
328
+ | PostgresqlConnectionConfig
329
+ | MysqlConnectionConfig;
325
330
 
326
- export type DatabaseConnectionName = keyof DatabaseConnections;
327
- export type DatabaseConnectionConfig = DatabaseConnections[DatabaseConnectionName];
331
+ /**
332
+ * Named database connection configs.
333
+ *
334
+ * Keys represent connection names (e.g. 'default', 'auth', 'tasks', 'db1').
335
+ */
336
+ export type DatabaseConnections = Record<string, DatabaseConnectionConfig>;
328
337
 
338
+ /**
339
+ * Default connection name.
340
+ */
329
341
  export type DatabaseConfigShape = {
330
- default: DatabaseConnectionName;
342
+ default: string;
331
343
  connections: DatabaseConnections;
332
344
  };
333
345
 
@@ -382,13 +394,7 @@ export type CacheDriverConfig =
382
394
  | KvCacheDriverConfig
383
395
  | KvRemoteCacheDriverConfig;
384
396
 
385
- export type CacheDrivers = {
386
- memory: MemoryCacheDriverConfig;
387
- redis: RedisCacheDriverConfig;
388
- mongodb: MongoCacheDriverConfig;
389
- kv: KvCacheDriverConfig;
390
- 'kv-remote': KvRemoteCacheDriverConfig;
391
- };
397
+ export type CacheDrivers = Record<string, CacheDriverConfig>;
392
398
 
393
399
  export type CacheConfigInput = {
394
400
  default: string;
@@ -430,3 +436,10 @@ export type KnownBroadcastDriverConfig =
430
436
  | PusherBroadcastDriverConfig
431
437
  | RedisBroadcastDriverConfig
432
438
  | RedisHttpsBroadcastDriverConfig;
439
+
440
+ export type BroadcastDrivers = Record<string, KnownBroadcastDriverConfig>;
441
+
442
+ export type BroadcastConfigInput = {
443
+ default: string;
444
+ drivers: BroadcastDrivers;
445
+ };
@@ -3,17 +3,13 @@
3
3
  * Provides health, liveness, and readiness endpoints.
4
4
  */
5
5
 
6
- import {
7
- Env,
8
- Logger,
9
- QueryBuilder,
10
- RuntimeHealthProbes,
11
- type IRouter,
12
- Router,
13
- useDatabase,
14
- } from '@zintrust/core';
15
-
16
- import { appConfig } from '../config';
6
+ import { appConfig } from '../config/app';
7
+ import { Env } from '../config/env';
8
+ import { Logger } from '../config/logger';
9
+ import { RuntimeHealthProbes } from '@zintrust/core';
10
+ import { useDatabase } from '@zintrust/core';
11
+ import { QueryBuilder } from '@zintrust/core';
12
+ import { type IRouter, Router } from '@zintrust/core';
17
13
 
18
14
  export function registerHealthRoutes(router: IRouter): void {
19
15
  registerHealthRoute(router);
@@ -27,6 +23,13 @@ function registerHealthRoute(router: IRouter): void {
27
23
 
28
24
  try {
29
25
  const db = useDatabase();
26
+ const maybeIsConnected = (db as unknown as { isConnected?: unknown }).isConnected;
27
+ const maybeConnect = (db as unknown as { connect?: unknown }).connect;
28
+ if (typeof maybeIsConnected === 'function' && maybeIsConnected.call(db) === false) {
29
+ if (typeof maybeConnect === 'function') {
30
+ await maybeConnect.call(db);
31
+ }
32
+ }
30
33
  await QueryBuilder.ping(db);
31
34
 
32
35
  const uptime =
@@ -79,6 +82,13 @@ function registerHealthReadyRoute(router: IRouter): void {
79
82
 
80
83
  try {
81
84
  const db = useDatabase();
85
+ const maybeIsConnected = (db as unknown as { isConnected?: unknown }).isConnected;
86
+ const maybeConnect = (db as unknown as { connect?: unknown }).connect;
87
+ if (typeof maybeIsConnected === 'function' && maybeIsConnected.call(db) === false) {
88
+ if (typeof maybeConnect === 'function') {
89
+ await maybeConnect.call(db);
90
+ }
91
+ }
82
92
  await QueryBuilder.ping(db);
83
93
 
84
94
  databaseResponseTime = Date.now() - startTime;
@@ -1,7 +1,9 @@
1
+ type Broadcaster = Readonly<{
2
+ send: (channel: string, event: string, data: unknown) => Promise<unknown>;
3
+ }>;
1
4
  export declare const Broadcast: Readonly<{
2
- send(channel: string, event: string, data: unknown): Promise<{
3
- ok: boolean;
4
- }>;
5
+ send(channel: string, event: string, data: unknown): Promise<unknown>;
6
+ broadcaster(name?: string): Broadcaster;
5
7
  }>;
6
8
  export default Broadcast;
7
9
  //# sourceMappingURL=Broadcast.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Broadcast.d.ts","sourceRoot":"","sources":["../../../../src/tools/broadcast/Broadcast.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,SAAS;kBACA,MAAM,SAAS,MAAM,QAAQ,OAAO;;;EAmCxD,CAAC;AAEH,eAAe,SAAS,CAAC"}
1
+ {"version":3,"file":"Broadcast.d.ts","sourceRoot":"","sources":["../../../../src/tools/broadcast/Broadcast.ts"],"names":[],"mappings":"AAQA,KAAK,WAAW,GAAG,QAAQ,CAAC;IAC1B,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC3E,CAAC,CAAC;AAyDH,eAAO,MAAM,SAAS;kBACA,MAAM,SAAS,MAAM,QAAQ,OAAO;uBAKrC,MAAM,GAAG,WAAW;EAQvC,CAAC;AAEH,eAAe,SAAS,CAAC"}
@@ -4,34 +4,58 @@ import { RedisDriver } from './drivers/Redis.js';
4
4
  import { RedisHttpsDriver } from './drivers/RedisHttps.js';
5
5
  import broadcastConfig from '../../config/broadcast.js';
6
6
  import { ErrorFactory } from '../../exceptions/ZintrustError.js';
7
- export const Broadcast = Object.freeze({
8
- async send(channel, event, data) {
9
- const driver = broadcastConfig.getDriverName();
10
- const config = broadcastConfig.getDriverConfig();
11
- if (driver === 'inmemory') {
12
- const result = await InMemoryDriver.send(undefined, channel, event, data);
13
- return result;
7
+ const resolveBroadcasterConfig = async (name) => {
8
+ const selection = (name ?? broadcastConfig.getDriverName()).toString().trim().toLowerCase();
9
+ try {
10
+ const { BroadcastRegistry } = await import('./BroadcastRegistry.js');
11
+ if (BroadcastRegistry.has(selection)) {
12
+ return BroadcastRegistry.get(selection);
14
13
  }
15
- if (driver === 'pusher') {
16
- if (config.driver !== 'pusher') {
17
- throw ErrorFactory.createConfigError('Broadcast driver config mismatch: expected pusher');
18
- }
19
- return PusherDriver.send(config, channel, event, data);
14
+ try {
15
+ const { registerBroadcastersFromRuntimeConfig } = await import('./BroadcastRuntimeRegistration.js');
16
+ registerBroadcastersFromRuntimeConfig(broadcastConfig);
20
17
  }
21
- if (driver === 'redis') {
22
- if (config.driver !== 'redis') {
23
- throw ErrorFactory.createConfigError('Broadcast driver config mismatch: expected redis');
24
- }
25
- return RedisDriver.send(config, channel, event, data);
18
+ catch {
19
+ // best-effort
26
20
  }
27
- if (driver === 'redishttps') {
28
- if (config.driver !== 'redishttps') {
29
- throw ErrorFactory.createConfigError('Broadcast driver config mismatch: expected redishttps');
30
- }
31
- return RedisHttpsDriver.send(config, channel, event, data);
21
+ if (BroadcastRegistry.has(selection)) {
22
+ return BroadcastRegistry.get(selection);
32
23
  }
33
- const err = ErrorFactory.createConfigError(`Broadcast driver not implemented: ${driver}`);
34
- throw err;
24
+ }
25
+ catch {
26
+ // best-effort
27
+ }
28
+ // Fallback to config lookup (throws on explicit unknown).
29
+ return broadcastConfig.getDriverConfig(name);
30
+ };
31
+ const sendWithConfig = async (config, channel, event, data) => {
32
+ const driverName = config.driver;
33
+ if (driverName === 'inmemory') {
34
+ return InMemoryDriver.send(undefined, channel, event, data);
35
+ }
36
+ if (driverName === 'pusher') {
37
+ return PusherDriver.send(config, channel, event, data);
38
+ }
39
+ if (driverName === 'redis') {
40
+ return RedisDriver.send(config, channel, event, data);
41
+ }
42
+ if (driverName === 'redishttps') {
43
+ return RedisHttpsDriver.send(config, channel, event, data);
44
+ }
45
+ throw ErrorFactory.createConfigError(`Broadcast driver not implemented: ${driverName}`);
46
+ };
47
+ export const Broadcast = Object.freeze({
48
+ async send(channel, event, data) {
49
+ const config = await resolveBroadcasterConfig();
50
+ return sendWithConfig(config, channel, event, data);
51
+ },
52
+ broadcaster(name) {
53
+ return Object.freeze({
54
+ send: async (channel, event, data) => {
55
+ const config = await resolveBroadcasterConfig(name);
56
+ return sendWithConfig(config, channel, event, data);
57
+ },
58
+ });
35
59
  },
36
60
  });
37
61
  export default Broadcast;
@@ -0,0 +1,15 @@
1
+ import type { KnownBroadcastDriverConfig } from '../../config/type';
2
+ declare function register(name: string, config: KnownBroadcastDriverConfig): void;
3
+ declare function get(name: string): KnownBroadcastDriverConfig;
4
+ declare function has(name: string): boolean;
5
+ declare function list(): string[];
6
+ declare function reset(): void;
7
+ export declare const BroadcastRegistry: Readonly<{
8
+ register: typeof register;
9
+ get: typeof get;
10
+ has: typeof has;
11
+ list: typeof list;
12
+ reset: typeof reset;
13
+ }>;
14
+ export {};
15
+ //# sourceMappingURL=BroadcastRegistry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BroadcastRegistry.d.ts","sourceRoot":"","sources":["../../../../src/tools/broadcast/BroadcastRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAC;AAQ/D,iBAAS,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,0BAA0B,GAAG,IAAI,CAExE;AAED,iBAAS,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,0BAA0B,CAKrD;AAED,iBAAS,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAElC;AAED,iBAAS,IAAI,IAAI,MAAM,EAAE,CAExB;AAED,iBAAS,KAAK,IAAI,IAAI,CAErB;AAED,eAAO,MAAM,iBAAiB;;;;;;EAM5B,CAAC"}
@@ -0,0 +1,29 @@
1
+ import { ErrorFactory } from '../../exceptions/ZintrustError.js';
2
+ const registry = new Map();
3
+ const normalize = (value) => value.trim().toLowerCase();
4
+ function register(name, config) {
5
+ registry.set(normalize(name), config);
6
+ }
7
+ function get(name) {
8
+ const key = normalize(name);
9
+ const found = registry.get(key);
10
+ if (found !== undefined)
11
+ return found;
12
+ throw ErrorFactory.createConfigError(`Broadcast driver not configured: ${key}`);
13
+ }
14
+ function has(name) {
15
+ return registry.has(normalize(name));
16
+ }
17
+ function list() {
18
+ return Array.from(registry.keys());
19
+ }
20
+ function reset() {
21
+ registry.clear();
22
+ }
23
+ export const BroadcastRegistry = Object.freeze({
24
+ register,
25
+ get,
26
+ has,
27
+ list,
28
+ reset,
29
+ });
@@ -0,0 +1,11 @@
1
+ import type { BroadcastConfigInput } from '../../config/type';
2
+ /**
3
+ * Register broadcasters from runtime config.
4
+ *
5
+ * This follows the framework's config-driven availability pattern:
6
+ * - Every `broadcastConfig.drivers[name]` is registered under `name`.
7
+ * - The configured default name is also registered as `'default'`.
8
+ * - Unknown names throw when selected via `BroadcastRegistry.get(name)`.
9
+ */
10
+ export declare function registerBroadcastersFromRuntimeConfig(config: Pick<BroadcastConfigInput, 'default' | 'drivers'>): void;
11
+ //# sourceMappingURL=BroadcastRuntimeRegistration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BroadcastRuntimeRegistration.d.ts","sourceRoot":"","sources":["../../../../src/tools/broadcast/BroadcastRuntimeRegistration.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAIzD;;;;;;;GAOG;AACH,wBAAgB,qCAAqC,CACnD,MAAM,EAAE,IAAI,CAAC,oBAAoB,EAAE,SAAS,GAAG,SAAS,CAAC,GACxD,IAAI,CAWN"}
@@ -0,0 +1,20 @@
1
+ import { BroadcastRegistry } from './BroadcastRegistry.js';
2
+ /**
3
+ * Register broadcasters from runtime config.
4
+ *
5
+ * This follows the framework's config-driven availability pattern:
6
+ * - Every `broadcastConfig.drivers[name]` is registered under `name`.
7
+ * - The configured default name is also registered as `'default'`.
8
+ * - Unknown names throw when selected via `BroadcastRegistry.get(name)`.
9
+ */
10
+ export function registerBroadcastersFromRuntimeConfig(config) {
11
+ for (const [name, driverConfig] of Object.entries(config.drivers)) {
12
+ BroadcastRegistry.register(name, driverConfig);
13
+ }
14
+ const defaultName = (config.default ?? '').toString().trim().toLowerCase();
15
+ if (defaultName.length === 0)
16
+ return;
17
+ if (BroadcastRegistry.has(defaultName)) {
18
+ BroadcastRegistry.register('default', BroadcastRegistry.get(defaultName));
19
+ }
20
+ }
@@ -1,4 +1,6 @@
1
1
  export { Broadcast } from './Broadcast';
2
+ export { BroadcastRegistry } from './BroadcastRegistry';
3
+ export { registerBroadcastersFromRuntimeConfig } from './BroadcastRuntimeRegistration';
2
4
  export { BaseDriver } from './drivers/BaseDriver';
3
5
  export { InMemoryDriver } from './drivers/InMemory';
4
6
  export { PusherDriver } from './drivers/Pusher';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/tools/broadcast/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/tools/broadcast/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,qCAAqC,EAAE,MAAM,yCAAyC,CAAC;AAChG,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC"}
@@ -1,4 +1,6 @@
1
1
  export { Broadcast } from './Broadcast.js';
2
+ export { BroadcastRegistry } from './BroadcastRegistry.js';
3
+ export { registerBroadcastersFromRuntimeConfig } from './BroadcastRuntimeRegistration.js';
2
4
  export { BaseDriver } from './drivers/BaseDriver.js';
3
5
  export { InMemoryDriver } from './drivers/InMemory.js';
4
6
  export { PusherDriver } from './drivers/Pusher.js';
@@ -16,6 +16,14 @@ export type SendMailResult = {
16
16
  messageId?: string;
17
17
  };
18
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
+ }>;
19
27
  send(input: SendMailInput): Promise<SendMailResult>;
20
28
  }>;
21
29
  export default Mail;
@@ -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;AAuHF,eAAO,MAAM,IAAI;gBACG,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC;EAqBzD,CAAC;AAEH,eAAe,IAAI,CAAC"}
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"}
@@ -75,9 +75,9 @@ const sendWithDriver = async (driver, message) => {
75
75
  throw err;
76
76
  }
77
77
  };
78
- export const Mail = Object.freeze({
78
+ const createMailer = (name) => Object.freeze({
79
79
  async send(input) {
80
- const driver = mailConfig.getDriver();
80
+ const driver = mailConfig.getDriver(name);
81
81
  if (driver.driver === 'disabled') {
82
82
  const err = ErrorFactory.createConfigError('Mail driver is disabled (set MAIL_DRIVER)');
83
83
  throw err;
@@ -95,4 +95,17 @@ export const Mail = Object.freeze({
95
95
  });
96
96
  },
97
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
+ });
98
111
  export default Mail;
@@ -6,11 +6,13 @@ declare function register(driver: string, handler: MailSendHandler): void;
6
6
  declare function get(driver: string): MailSendHandler | undefined;
7
7
  declare function has(driver: string): boolean;
8
8
  declare function list(): string[];
9
+ declare function reset(): void;
9
10
  export declare const MailDriverRegistry: Readonly<{
10
11
  register: typeof register;
11
12
  get: typeof get;
12
13
  has: typeof has;
13
14
  list: typeof list;
15
+ reset: typeof reset;
14
16
  }>;
15
17
  export {};
16
18
  //# sourceMappingURL=MailDriverRegistry.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"MailDriverRegistry.d.ts","sourceRoot":"","sources":["../../../../src/tools/mail/MailDriverRegistry.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GAAG,CAC5B,MAAM,EAAE,OAAO,EACf,OAAO,EAAE,OAAO,KACb,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAIlD,iBAAS,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,IAAI,CAEhE;AAED,iBAAS,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAExD;AAED,iBAAS,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAEpC;AAED,iBAAS,IAAI,IAAI,MAAM,EAAE,CAExB;AAED,eAAO,MAAM,kBAAkB;;;;;EAK7B,CAAC"}
1
+ {"version":3,"file":"MailDriverRegistry.d.ts","sourceRoot":"","sources":["../../../../src/tools/mail/MailDriverRegistry.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GAAG,CAC5B,MAAM,EAAE,OAAO,EACf,OAAO,EAAE,OAAO,KACb,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAIlD,iBAAS,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,IAAI,CAEhE;AAED,iBAAS,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAExD;AAED,iBAAS,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAEpC;AAED,iBAAS,IAAI,IAAI,MAAM,EAAE,CAExB;AAED,iBAAS,KAAK,IAAI,IAAI,CAErB;AAED,eAAO,MAAM,kBAAkB;;;;;;EAM7B,CAAC"}
@@ -11,9 +11,13 @@ function has(driver) {
11
11
  function list() {
12
12
  return Array.from(registry.keys());
13
13
  }
14
+ function reset() {
15
+ registry.clear();
16
+ }
14
17
  export const MailDriverRegistry = Object.freeze({
15
18
  register,
16
19
  get,
17
20
  has,
18
21
  list,
22
+ reset,
19
23
  });
@@ -5,6 +5,9 @@
5
5
  */
6
6
  export declare const Notification: Readonly<{
7
7
  send: (recipient: string, message: string, options?: Record<string, unknown>) => Promise<unknown>;
8
+ channel: (name: string) => Readonly<{
9
+ send: (recipient: string, message: string, options?: Record<string, unknown>) => Promise<unknown>;
10
+ }>;
8
11
  listDrivers: () => string[];
9
12
  }>;
10
13
  export default Notification;
@@ -1 +1 @@
1
- {"version":3,"file":"Notification.d.ts","sourceRoot":"","sources":["../../../../src/tools/notification/Notification.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,eAAO,MAAM,YAAY;;;EAGvB,CAAC;AAEH,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"Notification.d.ts","sourceRoot":"","sources":["../../../../src/tools/notification/Notification.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,eAAO,MAAM,YAAY;;oBAEP,MAAM;0BAEM,MAAM,WAAW,MAAM,YAAY,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;EAItF,CAAC;AAEH,eAAe,YAAY,CAAC"}
@@ -6,6 +6,9 @@
6
6
  import { NotificationService } from './Service.js';
7
7
  export const Notification = Object.freeze({
8
8
  send: NotificationService.send,
9
+ channel: (name) => Object.freeze({
10
+ send: async (recipient, message, options) => NotificationService.sendVia(name, recipient, message, options),
11
+ }),
9
12
  listDrivers: NotificationService.listDrivers,
10
13
  });
11
14
  export default Notification;
@@ -0,0 +1,15 @@
1
+ import type { KnownNotificationDriverConfig } from '../../config/type';
2
+ declare function register(name: string, config: KnownNotificationDriverConfig): void;
3
+ declare function has(name: string): boolean;
4
+ declare function get(name: string): KnownNotificationDriverConfig;
5
+ declare function list(): string[];
6
+ declare function reset(): void;
7
+ export declare const NotificationChannelRegistry: Readonly<{
8
+ register: typeof register;
9
+ has: typeof has;
10
+ get: typeof get;
11
+ list: typeof list;
12
+ reset: typeof reset;
13
+ }>;
14
+ export default NotificationChannelRegistry;
15
+ //# sourceMappingURL=NotificationChannelRegistry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NotificationChannelRegistry.d.ts","sourceRoot":"","sources":["../../../../src/tools/notification/NotificationChannelRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,cAAc,CAAC;AAUlE,iBAAS,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,6BAA6B,GAAG,IAAI,CAI3E;AAED,iBAAS,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAElC;AAED,iBAAS,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,6BAA6B,CAOxD;AAED,iBAAS,IAAI,IAAI,MAAM,EAAE,CAExB;AAED,iBAAS,KAAK,IAAI,IAAI,CAErB;AAED,eAAO,MAAM,2BAA2B;;;;;;EAMtC,CAAC;AAEH,eAAe,2BAA2B,CAAC"}
@@ -0,0 +1,36 @@
1
+ import { ErrorFactory } from '../../exceptions/ZintrustError.js';
2
+ const registry = new Map();
3
+ const normalizeKey = (name) => String(name ?? '')
4
+ .trim()
5
+ .toLowerCase();
6
+ function register(name, config) {
7
+ const key = normalizeKey(name);
8
+ if (key === '')
9
+ return;
10
+ registry.set(key, config);
11
+ }
12
+ function has(name) {
13
+ return registry.has(normalizeKey(name));
14
+ }
15
+ function get(name) {
16
+ const key = normalizeKey(name);
17
+ const cfg = registry.get(key);
18
+ if (cfg === undefined) {
19
+ throw ErrorFactory.createConfigError(`Notification channel not registered: ${name}`);
20
+ }
21
+ return cfg;
22
+ }
23
+ function list() {
24
+ return Array.from(registry.keys()).sort((a, b) => a.localeCompare(b));
25
+ }
26
+ function reset() {
27
+ registry.clear();
28
+ }
29
+ export const NotificationChannelRegistry = Object.freeze({
30
+ register,
31
+ has,
32
+ get,
33
+ list,
34
+ reset,
35
+ });
36
+ export default NotificationChannelRegistry;
@@ -0,0 +1,13 @@
1
+ import type { NotificationConfigInput } from '../../config/type';
2
+ /**
3
+ * Register notification channels from runtime config.
4
+ *
5
+ * - Every `notificationConfig.drivers[name]` is registered under `name`.
6
+ * - The configured default is also registered as `default`.
7
+ */
8
+ export declare function registerNotificationChannelsFromRuntimeConfig(config: Pick<NotificationConfigInput, 'default' | 'drivers'>): void;
9
+ export declare const NotificationRuntimeRegistration: Readonly<{
10
+ registerNotificationChannelsFromRuntimeConfig: typeof registerNotificationChannelsFromRuntimeConfig;
11
+ }>;
12
+ export default NotificationRuntimeRegistration;
13
+ //# sourceMappingURL=NotificationRuntimeRegistration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NotificationRuntimeRegistration.d.ts","sourceRoot":"","sources":["../../../../src/tools/notification/NotificationRuntimeRegistration.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAG5D;;;;;GAKG;AACH,wBAAgB,6CAA6C,CAC3D,MAAM,EAAE,IAAI,CAAC,uBAAuB,EAAE,SAAS,GAAG,SAAS,CAAC,GAC3D,IAAI,CAWN;AAED,eAAO,MAAM,+BAA+B;;EAE1C,CAAC;AAEH,eAAe,+BAA+B,CAAC"}
@@ -0,0 +1,22 @@
1
+ import { NotificationChannelRegistry } from './NotificationChannelRegistry.js';
2
+ /**
3
+ * Register notification channels from runtime config.
4
+ *
5
+ * - Every `notificationConfig.drivers[name]` is registered under `name`.
6
+ * - The configured default is also registered as `default`.
7
+ */
8
+ export function registerNotificationChannelsFromRuntimeConfig(config) {
9
+ for (const [name, driverConfig] of Object.entries(config.drivers)) {
10
+ NotificationChannelRegistry.register(name, driverConfig);
11
+ }
12
+ const defaultName = (config.default ?? '').toString().trim().toLowerCase();
13
+ if (defaultName.length === 0)
14
+ return;
15
+ if (NotificationChannelRegistry.has(defaultName)) {
16
+ NotificationChannelRegistry.register('default', NotificationChannelRegistry.get(defaultName));
17
+ }
18
+ }
19
+ export const NotificationRuntimeRegistration = Object.freeze({
20
+ registerNotificationChannelsFromRuntimeConfig,
21
+ });
22
+ export default NotificationRuntimeRegistration;
@@ -1 +1 @@
1
- {"version":3,"file":"Registry.d.ts","sourceRoot":"","sources":["../../../../src/tools/notification/Registry.ts"],"names":[],"mappings":"AAIA,KAAK,UAAU,GAAG;IAChB,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC/F,CAAC;AAOF,eAAO,MAAM,oBAAoB;mBAChB,MAAM,UAAU,UAAU;cAI/B,MAAM,GAAG,UAAU;YAOrB,MAAM,EAAE;EAGhB,CAAC;AAEH,eAAe,oBAAoB,CAAC"}
1
+ {"version":3,"file":"Registry.d.ts","sourceRoot":"","sources":["../../../../src/tools/notification/Registry.ts"],"names":[],"mappings":"AAMA,KAAK,UAAU,GAAG;IAChB,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC/F,CAAC;AASF,eAAO,MAAM,oBAAoB;mBAChB,MAAM,UAAU,UAAU;cAI/B,MAAM,GAAG,UAAU;YAOrB,MAAM,EAAE;EAGhB,CAAC;AAEH,eAAe,oBAAoB,CAAC"}
@@ -1,9 +1,13 @@
1
1
  import { ErrorFactory } from '../../exceptions/ZintrustError.js';
2
2
  import { ConsoleDriver } from './drivers/Console.js';
3
+ import { SlackNotificationDriver } from './drivers/SlackNotification.js';
3
4
  import { TermiiDriver } from './drivers/Termii.js';
5
+ import { TwilioNotificationDriver } from './drivers/TwilioNotification.js';
4
6
  const drivers = new Map();
5
7
  drivers.set('termii', TermiiDriver);
6
8
  drivers.set('console', ConsoleDriver);
9
+ drivers.set('slack', SlackNotificationDriver);
10
+ drivers.set('twilio', TwilioNotificationDriver);
7
11
  export const NotificationRegistry = Object.freeze({
8
12
  register(name, driver) {
9
13
  drivers.set(name.toLowerCase(), driver);
@@ -1,5 +1,6 @@
1
1
  export declare const NotificationService: Readonly<{
2
2
  send(recipient: string, message: string, options?: Record<string, unknown>): Promise<unknown>;
3
+ sendVia(channelName: string, recipient: string, message: string, options?: Record<string, unknown>): Promise<unknown>;
3
4
  listDrivers(): string[];
4
5
  }>;
5
6
  export default NotificationService;
@@ -1 +1 @@
1
- {"version":3,"file":"Service.d.ts","sourceRoot":"","sources":["../../../../src/tools/notification/Service.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,mBAAmB;oBACR,MAAM,WAAW,MAAM,YAAW,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;mBAYhE,MAAM,EAAE;EAGvB,CAAC;AAEH,eAAe,mBAAmB,CAAC"}
1
+ {"version":3,"file":"Service.d.ts","sourceRoot":"","sources":["../../../../src/tools/notification/Service.ts"],"names":[],"mappings":"AAoEA,eAAO,MAAM,mBAAmB;oBACR,MAAM,WAAW,MAAM,YAAW,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;yBAUhE,MAAM,aACR,MAAM,WACR,MAAM,YACN,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;mBAgDnB,MAAM,EAAE;EAGvB,CAAC;AAEH,eAAe,mBAAmB,CAAC"}