@zintrust/core 0.1.13 → 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 +5 -0
  34. package/src/index.d.ts.map +1 -1
  35. package/src/index.js +5 -0
  36. package/src/node.d.ts +1 -3
  37. package/src/node.d.ts.map +1 -1
  38. package/src/node.js +1 -3
  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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zintrust/core",
3
- "version": "0.1.13",
3
+ "version": "0.1.14",
4
4
  "description": "Production-grade TypeScript backend framework for JavaScript",
5
5
  "homepage": "https://zintrust.com",
6
6
  "repository": {
@@ -1 +1 @@
1
- {"version":3,"file":"Application.d.ts","sourceRoot":"","sources":["../../../src/boot/Application.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,iBAAiB,EAAoB,MAAM,8BAA8B,CAAC;AAEnF,OAAO,EAAE,gBAAgB,EAAmB,MAAM,8BAA8B,CAAC;AACjF,OAAO,EAAE,KAAK,OAAO,EAAU,MAAM,kBAAkB,CAAC;AAOxD,MAAM,WAAW,YAAY;IAC3B,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,QAAQ,IAAI,OAAO,CAAC;IACpB,aAAa,IAAI,OAAO,CAAC;IACzB,YAAY,IAAI,OAAO,CAAC;IACxB,SAAS,IAAI,OAAO,CAAC;IACrB,cAAc,IAAI,MAAM,CAAC;IACzB,SAAS,IAAI,OAAO,CAAC;IACrB,YAAY,IAAI,iBAAiB,CAAC;IAClC,kBAAkB,IAAI,gBAAgB,CAAC;IACvC,WAAW,IAAI,MAAM,CAAC;CACvB;AA2LD;;GAEG;AACH,eAAO,MAAM,WAAW;IACtB;;OAEG;sBACe,MAAM,GAAG,YAAY;EAmDvC,CAAC;AAEH,eAAe,WAAW,CAAC"}
1
+ {"version":3,"file":"Application.d.ts","sourceRoot":"","sources":["../../../src/boot/Application.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,iBAAiB,EAAoB,MAAM,8BAA8B,CAAC;AAEnF,OAAO,EAAE,gBAAgB,EAAmB,MAAM,8BAA8B,CAAC;AACjF,OAAO,EAAE,KAAK,OAAO,EAAU,MAAM,kBAAkB,CAAC;AASxD,MAAM,WAAW,YAAY;IAC3B,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,QAAQ,IAAI,OAAO,CAAC;IACpB,aAAa,IAAI,OAAO,CAAC;IACzB,YAAY,IAAI,OAAO,CAAC;IACxB,SAAS,IAAI,OAAO,CAAC;IACrB,cAAc,IAAI,MAAM,CAAC;IACzB,SAAS,IAAI,OAAO,CAAC;IACrB,YAAY,IAAI,iBAAiB,CAAC;IAClC,kBAAkB,IAAI,gBAAgB,CAAC;IACvC,WAAW,IAAI,MAAM,CAAC;CACvB;AAkVD;;GAEG;AACH,eAAO,MAAM,WAAW;IACtB;;OAEG;sBACe,MAAM,GAAG,YAAY;EA0CvC,CAAC;AAEH,eAAe,WAAW,CAAC"}
@@ -2,13 +2,15 @@
2
2
  * Application - Framework core entry point
3
3
  * Handles application lifecycle, booting, and environment
4
4
  */
5
- import { appConfig } from '../config/index.js';
5
+ import { appConfig, cacheConfig, databaseConfig, queueConfig, storageConfig } from '../config/index.js';
6
6
  import { ServiceContainer } from '../container/ServiceContainer.js';
7
7
  import { StartupHealthChecks } from '../health/StartupHealthChecks.js';
8
8
  import { MiddlewareStack } from '../middleware/MiddlewareStack.js';
9
9
  import { Router } from '../routing/Router.js';
10
+ import broadcastConfig from '../config/broadcast.js';
10
11
  import { FeatureFlags } from '../config/features.js';
11
12
  import { Logger } from '../config/logger.js';
13
+ import notificationConfig from '../config/notification.js';
12
14
  import { StartupConfigValidator } from '../config/StartupConfigValidator.js';
13
15
  import * as path from '../node-singletons/path.js';
14
16
  import { pathToFileURL } from '../node-singletons/url.js';
@@ -55,6 +57,83 @@ const registerCoreInstances = (params) => {
55
57
  params.container.singleton('container', params.container);
56
58
  params.container.singleton('shutdownManager', params.shutdownManager);
57
59
  };
60
+ const registerFrameworkShutdownHooks = (shutdownManager) => {
61
+ // Register framework-level shutdown hooks for long-lived resources
62
+ // ConnectionManager may not be initialized; shutdownIfInitialized is safe
63
+ // Use dynamic import without top-level await to avoid transforming the module into an async module
64
+ import('../orm/ConnectionManager.js')
65
+ .then((mod) => {
66
+ shutdownManager.add(async () => mod.ConnectionManager.shutdownIfInitialized());
67
+ })
68
+ /* c8 ignore start */
69
+ .catch(() => {
70
+ /* ignore import failures in restrictive runtimes */
71
+ });
72
+ /* c8 ignore stop */
73
+ import('../orm/Database.js')
74
+ .then((mod) => {
75
+ shutdownManager.add(() => mod.resetDatabase());
76
+ })
77
+ /* c8 ignore start */
78
+ .catch(() => {
79
+ /* ignore import failures in restrictive runtimes */
80
+ });
81
+ /* c8 ignore stop */
82
+ import('../cache/Cache.js')
83
+ .then((mod) => {
84
+ shutdownManager.add(() => mod.Cache.reset());
85
+ })
86
+ /* c8 ignore start */
87
+ .catch(() => {
88
+ /* ignore import failures in restrictive runtimes */
89
+ });
90
+ /* c8 ignore stop */
91
+ import('../tools/broadcast/BroadcastRegistry.js')
92
+ .then((mod) => {
93
+ shutdownManager.add(() => mod.BroadcastRegistry.reset());
94
+ })
95
+ /* c8 ignore start */
96
+ .catch(() => {
97
+ /* ignore import failures in restrictive runtimes */
98
+ });
99
+ /* c8 ignore stop */
100
+ import('../tools/storage/StorageDiskRegistry.js')
101
+ .then((mod) => {
102
+ shutdownManager.add(() => mod.StorageDiskRegistry.reset());
103
+ })
104
+ /* c8 ignore start */
105
+ .catch(() => {
106
+ /* ignore import failures in restrictive runtimes */
107
+ });
108
+ /* c8 ignore stop */
109
+ import('../tools/notification/NotificationChannelRegistry.js')
110
+ .then((mod) => {
111
+ shutdownManager.add(() => mod.NotificationChannelRegistry.reset());
112
+ })
113
+ /* c8 ignore start */
114
+ .catch(() => {
115
+ /* ignore import failures in restrictive runtimes */
116
+ });
117
+ /* c8 ignore stop */
118
+ import('../tools/mail/MailDriverRegistry.js')
119
+ .then((mod) => {
120
+ shutdownManager.add(() => mod.MailDriverRegistry.reset());
121
+ })
122
+ /* c8 ignore start */
123
+ .catch(() => {
124
+ /* ignore import failures in restrictive runtimes */
125
+ });
126
+ /* c8 ignore stop */
127
+ import('../tools/queue/Queue.js')
128
+ .then((mod) => {
129
+ shutdownManager.add(() => mod.Queue.reset());
130
+ })
131
+ /* c8 ignore start */
132
+ .catch(() => {
133
+ /* ignore import failures in restrictive runtimes */
134
+ });
135
+ /* c8 ignore stop */
136
+ };
58
137
  const tryImportRoutesFromAppBase = async (resolvedBasePath) => {
59
138
  if (resolvedBasePath === '')
60
139
  return undefined;
@@ -126,6 +205,67 @@ const createLifecycle = (params) => {
126
205
  StartupConfigValidator.assertValid();
127
206
  FeatureFlags.initialize();
128
207
  await StartupHealthChecks.assertHealthy();
208
+ // Register ORM database connections from runtime config.
209
+ // This makes every `databaseConfig.connections[name]` available via `useDatabase(undefined, name)`.
210
+ // The configured default is also registered as 'default'.
211
+ try {
212
+ const { registerDatabasesFromRuntimeConfig } = await import('../orm/DatabaseRuntimeRegistration.js');
213
+ registerDatabasesFromRuntimeConfig(databaseConfig);
214
+ }
215
+ catch {
216
+ // best-effort: ignore in restrictive runtimes
217
+ }
218
+ // Register queue drivers from runtime config.
219
+ // Ensures default drivers like `sync` are available without manual registration.
220
+ try {
221
+ const { registerQueuesFromRuntimeConfig } = await import('../tools/queue/QueueRuntimeRegistration.js');
222
+ registerQueuesFromRuntimeConfig(queueConfig);
223
+ }
224
+ catch {
225
+ // best-effort: ignore in restrictive runtimes
226
+ }
227
+ // Register cache driver factories from runtime config.
228
+ // Ensures built-in drivers are available via the driver registry.
229
+ try {
230
+ const { registerCachesFromRuntimeConfig } = await import('../cache/CacheRuntimeRegistration.js');
231
+ registerCachesFromRuntimeConfig(cacheConfig);
232
+ }
233
+ catch {
234
+ // best-effort: ignore in restrictive runtimes
235
+ }
236
+ // Register broadcasters from runtime config.
237
+ // Ensures named broadcasters are available and unknown names throw when selected.
238
+ try {
239
+ const { registerBroadcastersFromRuntimeConfig } = await import('../tools/broadcast/BroadcastRuntimeRegistration.js');
240
+ registerBroadcastersFromRuntimeConfig({
241
+ default: broadcastConfig.default,
242
+ drivers: broadcastConfig.drivers,
243
+ });
244
+ }
245
+ catch {
246
+ // best-effort: ignore in restrictive runtimes
247
+ }
248
+ // Register storage disks from runtime config.
249
+ // Ensures named disks are available and 'default' is a reserved alias.
250
+ try {
251
+ const { registerDisksFromRuntimeConfig } = await import('../tools/storage/StorageRuntimeRegistration.js');
252
+ registerDisksFromRuntimeConfig(storageConfig);
253
+ }
254
+ catch {
255
+ // best-effort: ignore in restrictive runtimes
256
+ }
257
+ // Register notification channels from runtime config.
258
+ // Enables selecting named channels and reserves the `default` alias.
259
+ try {
260
+ const { registerNotificationChannelsFromRuntimeConfig } = await import('../tools/notification/NotificationRuntimeRegistration.js');
261
+ registerNotificationChannelsFromRuntimeConfig({
262
+ default: notificationConfig.default,
263
+ drivers: notificationConfig.drivers,
264
+ });
265
+ }
266
+ catch {
267
+ // best-effort: ignore in restrictive runtimes
268
+ }
129
269
  await initializeArtifactDirectories(params.resolvedBasePath);
130
270
  await registerRoutes(params.resolvedBasePath, params.router);
131
271
  // Register service providers
@@ -164,16 +304,7 @@ export const Application = Object.freeze({
164
304
  let booted = false;
165
305
  registerCorePaths(container, resolvedBasePath, joinFromBase);
166
306
  registerCoreInstances({ container, environment, router, middlewareStack, shutdownManager });
167
- // Register framework-level shutdown hooks for long-lived resources
168
- // ConnectionManager may not be initialized; shutdownIfInitialized is safe
169
- // Use dynamic import without top-level await to avoid transforming the module into an async module
170
- import('../orm/ConnectionManager.js')
171
- .then(({ ConnectionManager }) => {
172
- shutdownManager.add(async () => ConnectionManager.shutdownIfInitialized());
173
- })
174
- .catch(() => {
175
- /* ignore import failures in restrictive runtimes */
176
- });
307
+ registerFrameworkShutdownHooks(shutdownManager);
177
308
  const { boot, shutdown } = createLifecycle({
178
309
  environment,
179
310
  resolvedBasePath,
@@ -4,6 +4,14 @@
4
4
  * Sealed namespace pattern - all exports through Cache namespace
5
5
  */
6
6
  import { CacheDriver } from './CacheDriver';
7
+ type CacheStore = Readonly<{
8
+ get: <T>(key: string) => Promise<T | null>;
9
+ set: <T>(key: string, value: T, ttl?: number) => Promise<void>;
10
+ delete: (key: string) => Promise<void>;
11
+ clear: () => Promise<void>;
12
+ has: (key: string) => Promise<boolean>;
13
+ getDriver: () => CacheDriver;
14
+ }>;
7
15
  export declare const Cache: Readonly<{
8
16
  get: <T>(key: string) => Promise<T | null>;
9
17
  set: <T>(key: string, value: T, ttl?: number) => Promise<void>;
@@ -11,6 +19,8 @@ export declare const Cache: Readonly<{
11
19
  clear: () => Promise<void>;
12
20
  has: (key: string) => Promise<boolean>;
13
21
  getDriver: () => CacheDriver;
22
+ store: (name?: string) => CacheStore;
23
+ reset: () => void;
14
24
  }>;
15
25
  /**
16
26
  * Helper alias for cache
@@ -22,5 +32,8 @@ export declare const cache: Readonly<{
22
32
  clear: () => Promise<void>;
23
33
  has: (key: string) => Promise<boolean>;
24
34
  getDriver: () => CacheDriver;
35
+ store: (name?: string) => CacheStore;
36
+ reset: () => void;
25
37
  }>;
38
+ export {};
26
39
  //# sourceMappingURL=Cache.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Cache.d.ts","sourceRoot":"","sources":["../../../src/cache/Cache.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AA0GjD,eAAO,MAAM,KAAK;UA1CC,CAAC,OAAO,MAAM,KAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;UAQlC,CAAC,OAAO,MAAM,SAAS,CAAC,QAAQ,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;kBAOjD,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;iBAOtB,OAAO,CAAC,IAAI,CAAC;eAOb,MAAM,KAAG,OAAO,CAAC,OAAO,CAAC;qBAQ3B,WAAW;EAY/B,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,KAAK;UAtDC,CAAC,OAAO,MAAM,KAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;UAQlC,CAAC,OAAO,MAAM,SAAS,CAAC,QAAQ,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;kBAOjD,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;iBAOtB,OAAO,CAAC,IAAI,CAAC;eAOb,MAAM,KAAG,OAAO,CAAC,OAAO,CAAC;qBAQ3B,WAAW;EAiBP,CAAC"}
1
+ {"version":3,"file":"Cache.d.ts","sourceRoot":"","sources":["../../../src/cache/Cache.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAmHjD,KAAK,UAAU,GAAG,QAAQ,CAAC;IACzB,GAAG,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAC3C,GAAG,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/D,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACvC,SAAS,EAAE,MAAM,WAAW,CAAC;CAC9B,CAAC,CAAC;AA0CH,eAAO,MAAM,KAAK;UA1FC,CAAC,OAAO,MAAM,KAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;UAQlC,CAAC,OAAO,MAAM,SAAS,CAAC,QAAQ,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;kBAOjD,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;iBAOtB,OAAO,CAAC,IAAI,CAAC;eAOb,MAAM,KAAG,OAAO,CAAC,OAAO,CAAC;qBAQ3B,WAAW;mBAaX,MAAM,KAAG,UAAU;iBAmCvB,IAAI;EAcpB,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,KAAK;UAxGC,CAAC,OAAO,MAAM,KAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;UAQlC,CAAC,OAAO,MAAM,SAAS,CAAC,QAAQ,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;kBAOjD,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;iBAOtB,OAAO,CAAC,IAAI,CAAC;eAOb,MAAM,KAAG,OAAO,CAAC,OAAO,CAAC;qBAQ3B,WAAW;mBAaX,MAAM,KAAG,UAAU;iBAmCvB,IAAI;EAmBI,CAAC"}
@@ -11,7 +11,7 @@ import { MongoDriver } from './drivers/MongoDriver.js';
11
11
  import { RedisDriver } from './drivers/RedisDriver.js';
12
12
  import { cacheConfig } from '../config/cache.js';
13
13
  import { ErrorFactory } from '../exceptions/ZintrustError.js';
14
- let instance;
14
+ const instances = new Map();
15
15
  function buildDriver(driver) {
16
16
  const maybeCreate = driver.create;
17
17
  if (typeof maybeCreate === 'function') {
@@ -22,8 +22,8 @@ function buildDriver(driver) {
22
22
  }
23
23
  throw ErrorFactory.createGeneralError('Invalid cache driver export');
24
24
  }
25
- function resolveDriver() {
26
- const driverConfig = cacheConfig.getDriver();
25
+ function resolveDriver(storeName) {
26
+ const driverConfig = cacheConfig.getDriver(storeName);
27
27
  const externalFactory = CacheDriverRegistry.get(driverConfig.driver);
28
28
  if (externalFactory !== undefined) {
29
29
  return externalFactory(driverConfig);
@@ -43,9 +43,18 @@ function resolveDriver() {
43
43
  return buildDriver(MemoryDriver);
44
44
  }
45
45
  }
46
- function getDriverInstance() {
47
- instance ??= resolveDriver();
48
- return instance;
46
+ function getDriverInstance(storeName) {
47
+ const normalizedSelection = String(storeName ?? '')
48
+ .trim()
49
+ .toLowerCase();
50
+ const resolvedKey = normalizedSelection.length > 0 ? normalizedSelection : 'default';
51
+ const existing = instances.get(resolvedKey);
52
+ if (existing !== undefined)
53
+ return existing;
54
+ const selector = resolvedKey === 'default' ? undefined : resolvedKey;
55
+ const created = resolveDriver(selector);
56
+ instances.set(resolvedKey, created);
57
+ return created;
49
58
  }
50
59
  /**
51
60
  * Get an item from the cache
@@ -85,6 +94,37 @@ const has = async (key) => {
85
94
  const getDriver = () => {
86
95
  return getDriverInstance();
87
96
  };
97
+ const store = (name) => {
98
+ const getFromStore = async (key) => {
99
+ return getDriverInstance(name).get(key);
100
+ };
101
+ const setInStore = async (key, value, ttl) => {
102
+ await getDriverInstance(name).set(key, value, ttl);
103
+ };
104
+ const delFromStore = async (key) => {
105
+ await getDriverInstance(name).delete(key);
106
+ };
107
+ const clearStore = async () => {
108
+ await getDriverInstance(name).clear();
109
+ };
110
+ const hasInStore = async (key) => {
111
+ return getDriverInstance(name).has(key);
112
+ };
113
+ const getStoreDriver = () => {
114
+ return getDriverInstance(name);
115
+ };
116
+ return Object.freeze({
117
+ get: getFromStore,
118
+ set: setInStore,
119
+ delete: delFromStore,
120
+ clear: clearStore,
121
+ has: hasInStore,
122
+ getDriver: getStoreDriver,
123
+ });
124
+ };
125
+ const reset = () => {
126
+ instances.clear();
127
+ };
88
128
  // Sealed namespace with cache functionality
89
129
  export const Cache = Object.freeze({
90
130
  get,
@@ -93,6 +133,8 @@ export const Cache = Object.freeze({
93
133
  clear,
94
134
  has,
95
135
  getDriver,
136
+ store,
137
+ reset,
96
138
  });
97
139
  /**
98
140
  * Helper alias for cache
@@ -0,0 +1,11 @@
1
+ import type { CacheConfig } from '../config/cache';
2
+ /**
3
+ * Register cache drivers from runtime config.
4
+ *
5
+ * This follows the framework's config-driven availability pattern:
6
+ * - Built-in driver factories are registered so config entries can reference them.
7
+ * - Named cache stores are still resolved from `cacheConfig.drivers[storeName]`.
8
+ * - Unknown store names throw when explicitly selected via `cacheConfig.getDriver(name)`.
9
+ */
10
+ export declare function registerCachesFromRuntimeConfig(_config: CacheConfig): void;
11
+ //# sourceMappingURL=CacheRuntimeRegistration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CacheRuntimeRegistration.d.ts","sourceRoot":"","sources":["../../../src/cache/CacheRuntimeRegistration.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AASjD;;;;;;;GAOG;AACH,wBAAgB,+BAA+B,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,CAM1E"}
@@ -0,0 +1,21 @@
1
+ import { CacheDriverRegistry } from './CacheDriverRegistry.js';
2
+ import { KVDriver } from './drivers/KVDriver.js';
3
+ import { KVRemoteDriver } from './drivers/KVRemoteDriver.js';
4
+ import { MemoryDriver } from './drivers/MemoryDriver.js';
5
+ import { MongoDriver } from './drivers/MongoDriver.js';
6
+ import { RedisDriver } from './drivers/RedisDriver.js';
7
+ /**
8
+ * Register cache drivers from runtime config.
9
+ *
10
+ * This follows the framework's config-driven availability pattern:
11
+ * - Built-in driver factories are registered so config entries can reference them.
12
+ * - Named cache stores are still resolved from `cacheConfig.drivers[storeName]`.
13
+ * - Unknown store names throw when explicitly selected via `cacheConfig.getDriver(name)`.
14
+ */
15
+ export function registerCachesFromRuntimeConfig(_config) {
16
+ CacheDriverRegistry.register('memory', () => MemoryDriver.create());
17
+ CacheDriverRegistry.register('redis', () => RedisDriver.create());
18
+ CacheDriverRegistry.register('mongodb', () => MongoDriver.create());
19
+ CacheDriverRegistry.register('kv', () => KVDriver.create());
20
+ CacheDriverRegistry.register('kv-remote', () => KVRemoteDriver.create());
21
+ }
@@ -4,19 +4,33 @@
4
4
  * Centralizes broadcast driver selection and provider env mappings.
5
5
  * Driver selection must be dynamic (tests may mutate process.env).
6
6
  */
7
- import { KnownBroadcastDriverConfig } from './type';
7
+ import { InMemoryBroadcastDriverConfig, KnownBroadcastDriverConfig, PusherBroadcastDriverConfig, RedisBroadcastDriverConfig, RedisHttpsBroadcastDriverConfig } from './type';
8
8
  declare const _default: Readonly<{
9
9
  /**
10
- * Normalized broadcast driver name.
10
+ * Default broadcaster name (normalized).
11
+ */
12
+ readonly default: string;
13
+ /**
14
+ * Broadcast drivers.
11
15
  *
12
- * NOTE: Allows custom driver names (project-specific drivers), so returns string.
16
+ * You may add custom named broadcasters (e.g. `ops`, `billing`) that point to any
17
+ * known driver config.
18
+ */
19
+ readonly drivers: {
20
+ readonly inmemory: InMemoryBroadcastDriverConfig;
21
+ readonly pusher: PusherBroadcastDriverConfig;
22
+ readonly redis: RedisBroadcastDriverConfig;
23
+ readonly redishttps: RedisHttpsBroadcastDriverConfig;
24
+ };
25
+ /**
26
+ * Normalized broadcast driver name for the default broadcaster.
13
27
  */
14
28
  readonly getDriverName: () => string;
15
29
  /**
16
30
  * Get a config object for the currently selected driver.
17
31
  * Defaults to inmemory for unknown/unsupported names.
18
32
  */
19
- readonly getDriverConfig: () => KnownBroadcastDriverConfig;
33
+ readonly getDriverConfig: (name?: string) => KnownBroadcastDriverConfig;
20
34
  }>;
21
35
  export default _default;
22
36
  //# sourceMappingURL=broadcast.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"broadcast.d.ts","sourceRoot":"","sources":["../../../src/config/broadcast.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EACL,0BAA0B,EAI3B,MAAM,cAAc,CAAC;;IA6BpB;;;;OAIG;kCACc,MAAM;IAIvB;;;OAGG;oCACgB,0BAA0B;;AAW/C,wBAAiD"}
1
+ {"version":3,"file":"broadcast.d.ts","sourceRoot":"","sources":["../../../src/config/broadcast.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAGL,6BAA6B,EAC7B,0BAA0B,EAC1B,2BAA2B,EAC3B,0BAA0B,EAC1B,+BAA+B,EAChC,MAAM,cAAc,CAAC;;IA0EpB;;OAEG;sBACY,MAAM;IAIrB;;;;;OAKG;;2BAEe,6BAA6B;;;;;IAc/C;;OAEG;kCACc,MAAM;IAIvB;;;OAGG;sCACoB,MAAM,KAAG,0BAA0B;;AAK5D,wBAAiD"}
@@ -5,7 +5,19 @@
5
5
  * Driver selection must be dynamic (tests may mutate process.env).
6
6
  */
7
7
  import { Env } from './env.js';
8
+ import { ErrorFactory } from '../exceptions/ZintrustError.js';
8
9
  const normalizeDriverName = (value) => value.trim().toLowerCase();
10
+ const hasOwn = (obj, key) => {
11
+ return Object.prototype.hasOwnProperty.call(obj, key);
12
+ };
13
+ const getDefaultBroadcaster = (drivers) => {
14
+ const value = normalizeDriverName(Env.get('BROADCAST_DRIVER', 'inmemory'));
15
+ if (value.length > 0 && hasOwn(drivers, value)) {
16
+ return value;
17
+ }
18
+ // Backwards-compatible default.
19
+ return hasOwn(drivers, 'inmemory') ? 'inmemory' : (Object.keys(drivers)[0] ?? 'inmemory');
20
+ };
9
21
  const getPusherConfig = () => ({
10
22
  driver: 'pusher',
11
23
  appId: Env.get('PUSHER_APP_ID', ''),
@@ -27,28 +39,64 @@ const getRedisHttpsConfig = () => ({
27
39
  token: Env.get('REDIS_HTTPS_TOKEN', ''),
28
40
  channelPrefix: Env.get('BROADCAST_CHANNEL_PREFIX', 'broadcast:'),
29
41
  });
42
+ const getBroadcastDriver = (config, name) => {
43
+ const selected = normalizeDriverName(String(name ?? config.default));
44
+ const broadcasterName = selected === 'default' ? normalizeDriverName(config.default) : selected;
45
+ const isExplicitSelection = name !== undefined &&
46
+ String(name).trim().length > 0 &&
47
+ normalizeDriverName(String(name)) !== 'default';
48
+ if (broadcasterName.length > 0 && hasOwn(config.drivers, broadcasterName)) {
49
+ const resolved = config.drivers[broadcasterName];
50
+ if (resolved !== undefined)
51
+ return resolved;
52
+ }
53
+ if (isExplicitSelection) {
54
+ throw ErrorFactory.createConfigError(`Broadcast driver not configured: ${broadcasterName}`);
55
+ }
56
+ const fallback = config.drivers['inmemory'] ?? Object.values(config.drivers)[0];
57
+ if (fallback !== undefined)
58
+ return fallback;
59
+ throw ErrorFactory.createConfigError('No broadcast drivers are configured');
60
+ };
30
61
  const broadcastConfigObj = {
31
62
  /**
32
- * Normalized broadcast driver name.
63
+ * Default broadcaster name (normalized).
64
+ */
65
+ get default() {
66
+ return getDefaultBroadcaster(this.drivers);
67
+ },
68
+ /**
69
+ * Broadcast drivers.
33
70
  *
34
- * NOTE: Allows custom driver names (project-specific drivers), so returns string.
71
+ * You may add custom named broadcasters (e.g. `ops`, `billing`) that point to any
72
+ * known driver config.
73
+ */
74
+ drivers: {
75
+ get inmemory() {
76
+ return { driver: 'inmemory' };
77
+ },
78
+ get pusher() {
79
+ return getPusherConfig();
80
+ },
81
+ get redis() {
82
+ return getRedisConfig();
83
+ },
84
+ get redishttps() {
85
+ return getRedisHttpsConfig();
86
+ },
87
+ },
88
+ /**
89
+ * Normalized broadcast driver name for the default broadcaster.
35
90
  */
36
91
  getDriverName() {
37
- return normalizeDriverName(Env.get('BROADCAST_DRIVER', 'inmemory'));
92
+ return normalizeDriverName(this.default);
38
93
  },
39
94
  /**
40
95
  * Get a config object for the currently selected driver.
41
96
  * Defaults to inmemory for unknown/unsupported names.
42
97
  */
43
- getDriverConfig() {
44
- const driver = this.getDriverName();
45
- if (driver === 'pusher')
46
- return getPusherConfig();
47
- if (driver === 'redis')
48
- return getRedisConfig();
49
- if (driver === 'redishttps')
50
- return getRedisHttpsConfig();
51
- return { driver: 'inmemory' };
98
+ getDriverConfig(name) {
99
+ return getBroadcastDriver(this, name);
52
100
  },
53
101
  };
54
102
  export default Object.freeze(broadcastConfigObj);
@@ -41,7 +41,7 @@ export declare const cacheConfig: Readonly<{
41
41
  /**
42
42
  * Get cache driver config
43
43
  */
44
- getDriver(): CacheDriverConfig;
44
+ getDriver(name?: string): CacheDriverConfig;
45
45
  /**
46
46
  * Key prefix for all cache keys
47
47
  */
@@ -1 +1 @@
1
- {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../../src/config/cache.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAoB,iBAAiB,EAAgB,MAAM,cAAc,CAAC;AAmEjF,eAAO,MAAM,WAAW;IArDtB;;OAEG;;IAGH;;OAEG;;;;;;;;;;;;;;;;;;;;;;;;;;;IA4BH;;OAEG;iBACU,iBAAiB;IAI9B;;OAEG;;IAGH;;OAEG;;EAImD,CAAC;AACzD,MAAM,MAAM,WAAW,GAAG,OAAO,WAAW,CAAC"}
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../../src/config/cache.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAoB,iBAAiB,EAAE,MAAM,cAAc,CAAC;AA+EnE,eAAO,MAAM,WAAW;IArDtB;;OAEG;;IAGH;;OAEG;;;;;;;;;;;;;;;;;;;;;;;;;;;IA4BH;;OAEG;qBACc,MAAM,GAAG,iBAAiB;IAI3C;;OAEG;;IAGH;;OAEG;;EAImD,CAAC;AACzD,MAAM,MAAM,WAAW,GAAG,OAAO,WAAW,CAAC"}
@@ -4,13 +4,24 @@
4
4
  * Sealed namespace for immutability
5
5
  */
6
6
  import { Env } from './env.js';
7
- const getCacheDriver = (config) => {
8
- const defaultDriver = config.default;
9
- if (Object.hasOwn(config.drivers, defaultDriver)) {
10
- const driverName = defaultDriver;
11
- return config.drivers[driverName];
7
+ import { ErrorFactory } from '../exceptions/ZintrustError.js';
8
+ const getCacheDriver = (config, name) => {
9
+ const selected = String(name ?? config.default).trim();
10
+ const storeName = selected === 'default' ? String(config.default).trim() : selected;
11
+ const isExplicitSelection = name !== undefined && String(name).trim().length > 0 && String(name).trim() !== 'default';
12
+ if (storeName.length > 0 && Object.hasOwn(config.drivers, storeName)) {
13
+ const resolved = config.drivers[storeName];
14
+ if (resolved !== undefined)
15
+ return resolved;
12
16
  }
13
- return config.drivers.memory;
17
+ if (isExplicitSelection) {
18
+ throw ErrorFactory.createConfigError(`Cache store not configured: ${storeName}`);
19
+ }
20
+ // Backwards-compatible fallback.
21
+ const fallback = config.drivers['memory'] ?? Object.values(config.drivers)[0];
22
+ if (fallback !== undefined)
23
+ return fallback;
24
+ throw ErrorFactory.createConfigError('No cache stores are configured');
14
25
  };
15
26
  const cacheConfigObj = {
16
27
  /**
@@ -49,8 +60,8 @@ const cacheConfigObj = {
49
60
  /**
50
61
  * Get cache driver config
51
62
  */
52
- getDriver() {
53
- return getCacheDriver(this);
63
+ getDriver(name) {
64
+ return getCacheDriver(this, name);
54
65
  },
55
66
  /**
56
67
  * Key prefix for all cache keys
@@ -8,7 +8,7 @@ export declare const databaseConfig: Readonly<{
8
8
  /**
9
9
  * Default database connection
10
10
  */
11
- default: keyof import("./type").DatabaseConnections;
11
+ default: string;
12
12
  /**
13
13
  * Database connections
14
14
  */
@@ -1 +1 @@
1
- {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../../src/config/database.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EACL,mBAAmB,EACnB,wBAAwB,EAEzB,MAAM,cAAc,CAAC;AA6FtB,eAAO,MAAM,cAAc;IA5EzB;;OAEG;;IAGH;;OAEG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAsCH;;OAEG;wBACiB,mBAAmB,GAAG,wBAAwB;IAIlE;;OAEG;;;;;IAMH;;OAEG;;;;;IAMH;;OAEG;;;;EAMyD,CAAC;AAC/D,MAAM,MAAM,cAAc,GAAG,OAAO,cAAc,CAAC"}
1
+ {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../../src/config/database.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,mBAAmB,EAAE,wBAAwB,EAAuB,MAAM,cAAc,CAAC;AAkHlG,eAAO,MAAM,cAAc;IAzCzB;;OAEG;;IAGH;;OAEG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAGH;;OAEG;wBACiB,mBAAmB,GAAG,wBAAwB;IAIlE;;OAEG;;;;;IAMH;;OAEG;;;;;IAMH;;OAEG;;;;EAMyD,CAAC;AAC/D,MAAM,MAAM,cAAc,GAAG,OAAO,cAAc,CAAC"}