@zintrust/core 0.1.21 → 0.1.23

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 (279) hide show
  1. package/bin/z.d.ts +1 -1
  2. package/bin/z.js +1 -1
  3. package/bin/zin.d.ts +1 -1
  4. package/bin/zin.js +1 -1
  5. package/bin/zintrust-main.d.ts +1 -1
  6. package/bin/zintrust-main.js +2 -2
  7. package/bin/zintrust-microservices.d.ts +1 -1
  8. package/bin/zintrust-microservices.js +1 -1
  9. package/bin/zintrust.d.ts +1 -1
  10. package/bin/zintrust.js +1 -1
  11. package/bin/zt.d.ts +1 -1
  12. package/bin/zt.js +1 -1
  13. package/package.json +2 -3
  14. package/public/index.html +3 -3
  15. package/routes/api.js +1 -1
  16. package/routes/health.d.ts +3 -4
  17. package/routes/health.d.ts.map +1 -1
  18. package/routes/health.js +3 -125
  19. package/src/boot/Application.d.ts.map +1 -1
  20. package/src/boot/Application.js +11 -22
  21. package/src/boot/bootstrap.d.ts +1 -1
  22. package/src/boot/bootstrap.js +48 -7
  23. package/src/builder/BundleOptimizer.d.ts +1 -1
  24. package/src/builder/BundleOptimizer.js +1 -1
  25. package/src/cache/drivers/KVRemoteDriver.d.ts +1 -1
  26. package/src/cache/drivers/KVRemoteDriver.js +1 -1
  27. package/src/cli/CLI.d.ts.map +1 -1
  28. package/src/cli/CLI.js +15 -1
  29. package/src/cli/ErrorHandler.js +3 -3
  30. package/src/cli/commands/AddCommand.d.ts +1 -1
  31. package/src/cli/commands/AddCommand.d.ts.map +1 -1
  32. package/src/cli/commands/AddCommand.js +1 -1
  33. package/src/cli/commands/DbSeedCommand.js +1 -1
  34. package/src/cli/commands/MakeMailTemplateCommand.js +2 -1
  35. package/src/cli/commands/MakeNotificationTemplateCommand.js +2 -1
  36. package/src/cli/commands/MigrateCommand.d.ts.map +1 -1
  37. package/src/cli/commands/MigrateCommand.js +1 -1
  38. package/src/cli/commands/MigrateWorkerCommand.d.ts +9 -0
  39. package/src/cli/commands/MigrateWorkerCommand.d.ts.map +1 -0
  40. package/src/cli/commands/MigrateWorkerCommand.js +182 -0
  41. package/src/cli/commands/NewCommand.d.ts +1 -1
  42. package/src/cli/commands/NewCommand.d.ts.map +1 -1
  43. package/src/cli/commands/NewCommand.js +21 -7
  44. package/src/cli/commands/PublishCommand.d.ts +5 -0
  45. package/src/cli/commands/PublishCommand.d.ts.map +1 -0
  46. package/src/cli/commands/PublishCommand.js +54 -0
  47. package/src/cli/commands/QACommand.js +4 -4
  48. package/src/cli/commands/ResourceControlCommand.d.ts +6 -0
  49. package/src/cli/commands/ResourceControlCommand.d.ts.map +1 -0
  50. package/src/cli/commands/ResourceControlCommand.js +43 -0
  51. package/src/cli/commands/SimulateCommand.d.ts +1 -1
  52. package/src/cli/commands/SimulateCommand.js +4 -4
  53. package/src/cli/commands/StartCommand.d.ts.map +1 -1
  54. package/src/cli/commands/StartCommand.js +19 -7
  55. package/src/cli/commands/UpgradeCommand.d.ts +1 -1
  56. package/src/cli/commands/UpgradeCommand.js +2 -2
  57. package/src/cli/commands/WorkerCommands.d.ts +17 -0
  58. package/src/cli/commands/WorkerCommands.d.ts.map +1 -0
  59. package/src/cli/commands/WorkerCommands.js +264 -0
  60. package/src/cli/commands/index.d.ts +2 -0
  61. package/src/cli/commands/index.d.ts.map +1 -1
  62. package/src/cli/commands/index.js +2 -0
  63. package/src/cli/config/ConfigSchema.d.ts +1 -1
  64. package/src/cli/config/ConfigSchema.d.ts.map +1 -1
  65. package/src/cli/config/ConfigSchema.js +4 -3
  66. package/src/cli/d1/D1SqlMigrations.d.ts.map +1 -1
  67. package/src/cli/d1/D1SqlMigrations.js +4 -3
  68. package/src/cli/scaffolding/ModelGenerator.d.ts +1 -1
  69. package/src/cli/scaffolding/ModelGenerator.d.ts.map +1 -1
  70. package/src/cli/scaffolding/ModelGenerator.js +10 -2
  71. package/src/cli/scaffolding/ProjectScaffolder.js +5 -5
  72. package/src/cli/scaffolding/RouteGenerator.d.ts.map +1 -1
  73. package/src/cli/scaffolding/RouteGenerator.js +21 -2
  74. package/src/cli/scaffolding/TemplateEngine.js +1 -1
  75. package/src/cli/utils/EnvFileLoader.d.ts.map +1 -1
  76. package/src/common/ExternalServiceUtils.d.ts +63 -0
  77. package/src/common/ExternalServiceUtils.d.ts.map +1 -0
  78. package/src/common/ExternalServiceUtils.js +116 -0
  79. package/src/common/HealthRoutes.d.ts +10 -0
  80. package/src/common/HealthRoutes.d.ts.map +1 -0
  81. package/src/common/HealthRoutes.js +114 -0
  82. package/src/config/SecretsManager.d.ts.map +1 -1
  83. package/src/config/SecretsManager.js +2 -1
  84. package/src/config/app.d.ts +2 -1
  85. package/src/config/app.d.ts.map +1 -1
  86. package/src/config/app.js +98 -52
  87. package/src/config/broadcast.d.ts.map +1 -1
  88. package/src/config/broadcast.js +2 -2
  89. package/src/config/cache.d.ts.map +1 -1
  90. package/src/config/cache.js +2 -2
  91. package/src/config/database.d.ts.map +1 -1
  92. package/src/config/database.js +24 -5
  93. package/src/config/env.d.ts +43 -1
  94. package/src/config/env.d.ts.map +1 -1
  95. package/src/config/env.js +68 -21
  96. package/src/config/index.d.ts +10 -1
  97. package/src/config/index.d.ts.map +1 -1
  98. package/src/config/index.js +1 -0
  99. package/src/config/mail.d.ts.map +1 -1
  100. package/src/config/mail.js +3 -3
  101. package/src/config/middleware.d.ts.map +1 -1
  102. package/src/config/middleware.js +1 -1
  103. package/src/config/notification.d.ts.map +1 -1
  104. package/src/config/notification.js +2 -2
  105. package/src/config/queue.d.ts +14 -0
  106. package/src/config/queue.d.ts.map +1 -1
  107. package/src/config/queue.js +61 -36
  108. package/src/config/security.js +2 -2
  109. package/src/config/storage.d.ts.map +1 -1
  110. package/src/config/storage.js +5 -5
  111. package/src/config/type.d.ts +122 -0
  112. package/src/config/type.d.ts.map +1 -1
  113. package/src/config/type.js +10 -1
  114. package/src/config/workers.d.ts +13 -0
  115. package/src/config/workers.d.ts.map +1 -0
  116. package/src/config/workers.js +173 -0
  117. package/src/database/Paginator.d.ts +37 -0
  118. package/src/database/Paginator.d.ts.map +1 -0
  119. package/src/database/Paginator.js +81 -0
  120. package/src/exceptions/ZintrustError.d.ts +5 -2
  121. package/src/exceptions/ZintrustError.d.ts.map +1 -1
  122. package/src/exceptions/ZintrustError.js +6 -2
  123. package/src/features/Auth.d.ts +1 -1
  124. package/src/features/Auth.d.ts.map +1 -1
  125. package/src/features/Auth.js +3 -2
  126. package/src/features/Queue.d.ts.map +1 -1
  127. package/src/features/Queue.js +0 -2
  128. package/src/index.d.ts +15 -5
  129. package/src/index.d.ts.map +1 -1
  130. package/src/index.js +24 -3
  131. package/src/microservices/MicroserviceBootstrap.d.ts.map +1 -1
  132. package/src/microservices/MicroserviceBootstrap.js +3 -1
  133. package/src/microservices/MicroserviceGenerator.js +4 -4
  134. package/src/microservices/MicroserviceManager.d.ts +1 -1
  135. package/src/microservices/MicroserviceManager.js +1 -1
  136. package/src/middleware/RateLimiter.d.ts.map +1 -1
  137. package/src/middleware/RateLimiter.js +4 -3
  138. package/src/migrations/MigrationLoader.d.ts +1 -1
  139. package/src/migrations/MigrationLoader.d.ts.map +1 -1
  140. package/src/migrations/Migrator.d.ts +3 -3
  141. package/src/migrations/Migrator.d.ts.map +1 -1
  142. package/src/migrations/Migrator.js +1 -1
  143. package/src/migrations/MigratorFactory.d.ts +1 -1
  144. package/src/migrations/MigratorFactory.d.ts.map +1 -1
  145. package/src/migrations/MigratorFactory.js +3 -3
  146. package/src/migrations/enum/index.d.ts +93 -0
  147. package/src/migrations/enum/index.d.ts.map +1 -0
  148. package/src/migrations/enum/index.js +92 -0
  149. package/src/migrations/schema/Blueprint.d.ts +1 -1
  150. package/src/migrations/schema/Blueprint.d.ts.map +1 -1
  151. package/src/migrations/schema/Blueprint.js +27 -25
  152. package/src/migrations/schema/Schema.d.ts +1 -1
  153. package/src/migrations/schema/Schema.d.ts.map +1 -1
  154. package/src/migrations/schema/Schema.js +4 -3
  155. package/src/migrations/schema/SchemaCompiler.d.ts +1 -1
  156. package/src/migrations/schema/SchemaCompiler.d.ts.map +1 -1
  157. package/src/migrations/schema/SchemaCompiler.js +99 -91
  158. package/src/migrations/schema/index.d.ts +4 -4
  159. package/src/migrations/schema/index.d.ts.map +1 -1
  160. package/src/migrations/schema/index.js +3 -3
  161. package/src/migrations/schema/types.d.ts +2 -1
  162. package/src/migrations/schema/types.d.ts.map +1 -1
  163. package/src/node-singletons/crypto.d.ts +1 -1
  164. package/src/node-singletons/crypto.d.ts.map +1 -1
  165. package/src/node-singletons/crypto.js +1 -1
  166. package/src/node-singletons/os.d.ts +10 -1
  167. package/src/node-singletons/os.d.ts.map +1 -1
  168. package/src/node-singletons/os.js +10 -1
  169. package/src/openapi/OpenApiGenerator.js +2 -2
  170. package/src/orm/ConnectionManager.d.ts +7 -5
  171. package/src/orm/ConnectionManager.d.ts.map +1 -1
  172. package/src/orm/ConnectionManager.js +249 -93
  173. package/src/orm/Database.d.ts +2 -1
  174. package/src/orm/Database.d.ts.map +1 -1
  175. package/src/orm/DatabaseAdapter.d.ts +3 -2
  176. package/src/orm/DatabaseAdapter.d.ts.map +1 -1
  177. package/src/orm/DatabaseAdapter.js +17 -0
  178. package/src/orm/Model.d.ts +8 -1
  179. package/src/orm/Model.d.ts.map +1 -1
  180. package/src/orm/Model.js +109 -26
  181. package/src/orm/QueryBuilder.d.ts +12 -2
  182. package/src/orm/QueryBuilder.d.ts.map +1 -1
  183. package/src/orm/QueryBuilder.js +438 -38
  184. package/src/orm/Relationships.d.ts +61 -1
  185. package/src/orm/Relationships.d.ts.map +1 -1
  186. package/src/orm/Relationships.js +190 -0
  187. package/src/orm/adapters/D1Adapter.d.ts.map +1 -1
  188. package/src/orm/adapters/D1Adapter.js +2 -1
  189. package/src/orm/adapters/D1RemoteAdapter.d.ts +1 -1
  190. package/src/orm/adapters/D1RemoteAdapter.d.ts.map +1 -1
  191. package/src/orm/adapters/D1RemoteAdapter.js +3 -2
  192. package/src/orm/adapters/MySQLAdapter.d.ts.map +1 -1
  193. package/src/orm/adapters/MySQLAdapter.js +2 -1
  194. package/src/orm/adapters/SQLServerAdapter.d.ts.map +1 -1
  195. package/src/orm/adapters/SQLServerAdapter.js +2 -1
  196. package/src/orm/adapters/SQLiteAdapter.d.ts.map +1 -1
  197. package/src/orm/adapters/SQLiteAdapter.js +2 -1
  198. package/src/orm/migrations/MigrationStore.d.ts.map +1 -1
  199. package/src/performance/Optimizer.d.ts.map +1 -1
  200. package/src/performance/Optimizer.js +57 -18
  201. package/src/profiling/RequestProfiler.d.ts.map +1 -1
  202. package/src/profiling/RequestProfiler.js +3 -1
  203. package/src/routing/CoreRoutes.d.ts +1 -1
  204. package/src/routing/CoreRoutes.d.ts.map +1 -1
  205. package/src/routing/CoreRoutes.js +2 -116
  206. package/src/routing/error.d.ts.map +1 -1
  207. package/src/routing/error.js +3 -2
  208. package/src/routing/publicRoot.d.ts.map +1 -1
  209. package/src/routing/publicRoot.js +4 -2
  210. package/src/runtime/PluginAutoImports.d.ts.map +1 -1
  211. package/src/runtime/PluginAutoImports.js +20 -4
  212. package/src/runtime/PluginManager.d.ts.map +1 -1
  213. package/src/runtime/PluginManager.js +23 -6
  214. package/src/runtime/RuntimeAdapter.d.ts +3 -3
  215. package/src/runtime/RuntimeAdapter.d.ts.map +1 -1
  216. package/src/runtime/StartupConfigFileRegistry.d.ts +15 -13
  217. package/src/runtime/StartupConfigFileRegistry.d.ts.map +1 -1
  218. package/src/runtime/StartupConfigFileRegistry.js +12 -12
  219. package/src/runtime/adapters/CloudflareAdapter.d.ts.map +1 -1
  220. package/src/runtime/adapters/CloudflareAdapter.js +1 -1
  221. package/src/runtime/adapters/DenoAdapter.d.ts.map +1 -1
  222. package/src/runtime/adapters/DenoAdapter.js +1 -1
  223. package/src/runtime/adapters/FargateAdapter.d.ts +2 -2
  224. package/src/runtime/adapters/FargateAdapter.d.ts.map +1 -1
  225. package/src/runtime/adapters/FargateAdapter.js +1 -1
  226. package/src/runtime/adapters/LambdaAdapter.d.ts +1 -1
  227. package/src/runtime/adapters/LambdaAdapter.d.ts.map +1 -1
  228. package/src/runtime/adapters/LambdaAdapter.js +6 -4
  229. package/src/runtime/adapters/NodeServerAdapter.js +1 -1
  230. package/src/scripts/GenerateEnvArtifacts.js +1 -1
  231. package/src/security/SignedRequest.js +1 -1
  232. package/src/security/StartupSecretValidation.d.ts.map +1 -1
  233. package/src/security/StartupSecretValidation.js +7 -1
  234. package/src/start.d.ts.map +1 -1
  235. package/src/start.js +0 -2
  236. package/src/templates/features/Auth.ts.tpl +4 -4
  237. package/src/templates/project/basic/README.md.tpl +1 -1
  238. package/src/templates/project/basic/app/Middleware/index.ts.tpl +1 -1
  239. package/src/templates/project/basic/config/notification.ts.tpl +1 -1
  240. package/src/templates/project/basic/routes/api.ts.tpl +1 -3
  241. package/src/templates/project/basic/src/index.ts.tpl +1 -1
  242. package/src/templates/project/basic/src/zintrust.plugins.ts.tpl +1 -1
  243. package/src/templates/project/basic/template.json +1 -1
  244. package/src/toolkit/Secrets/index.d.ts.map +1 -1
  245. package/src/toolkit/Secrets/index.js +13 -9
  246. package/src/toolkit/Secrets/providers/AwsSecretsManager.d.ts.map +1 -1
  247. package/src/toolkit/Secrets/providers/AwsSecretsManager.js +20 -7
  248. package/src/toolkit/Secrets/providers/CloudflareKv.d.ts.map +1 -1
  249. package/src/toolkit/Secrets/providers/CloudflareKv.js +19 -6
  250. package/src/tools/http/Http.js +1 -1
  251. package/src/tools/mail/drivers/Ses.d.ts.map +1 -1
  252. package/src/tools/mail/drivers/Ses.js +5 -4
  253. package/src/tools/mail/templates/index.js +2 -2
  254. package/src/tools/notification/drivers/Termii.d.ts.map +1 -1
  255. package/src/tools/notification/drivers/Termii.js +6 -17
  256. package/src/tools/notification/testingHelpers.d.ts.map +1 -1
  257. package/src/tools/queue/Queue.d.ts.map +1 -1
  258. package/src/tools/queue/Queue.js +3 -5
  259. package/src/tools/queue/drivers/Redis.d.ts.map +1 -1
  260. package/src/tools/queue/drivers/Redis.js +7 -1
  261. package/src/tools/storage/drivers/S3.d.ts.map +1 -1
  262. package/src/tools/storage/drivers/S3.js +16 -3
  263. package/src/routes/health.d.ts +0 -2
  264. package/src/routes/health.d.ts.map +0 -1
  265. package/src/routes/health.js +0 -1
  266. package/src/runtime/RuntimeDetector.d.ts +0 -15
  267. package/src/runtime/RuntimeDetector.d.ts.map +0 -1
  268. package/src/runtime/RuntimeDetector.js +0 -271
  269. package/src/templates/project/basic/routes/health.ts.tpl +0 -143
  270. package/src/templates/project/basic/routes/metrics.ts.tpl +0 -22
  271. package/src/workers/BroadcastWorker.d.ts +0 -22
  272. package/src/workers/BroadcastWorker.d.ts.map +0 -1
  273. package/src/workers/BroadcastWorker.js +0 -24
  274. package/src/workers/NotificationWorker.d.ts +0 -22
  275. package/src/workers/NotificationWorker.d.ts.map +0 -1
  276. package/src/workers/NotificationWorker.js +0 -23
  277. package/src/workers/createQueueWorker.d.ts +0 -24
  278. package/src/workers/createQueueWorker.d.ts.map +0 -1
  279. package/src/workers/createQueueWorker.js +0 -114
@@ -1,10 +1,12 @@
1
1
  /**
2
- * Persistent Connection Manager for Zintrust Framework
2
+ * Persistent Connection Manager for ZinTrust Framework
3
3
  * Handles database connections across different runtime environments
4
4
  * Supports: PostgreSQL, MySQL, SQL Server with connection pooling for Lambda
5
5
  */
6
+ import type { SupportedDriver } from '../migrations/enum';
7
+ import type { IDatabaseAdapter } from './DatabaseAdapter';
6
8
  export interface ConnectionConfig {
7
- adapter: 'postgresql' | 'mysql' | 'sqlite' | 'sqlserver' | 'd1' | 'aurora-data-api';
9
+ adapter: SupportedDriver;
8
10
  host?: string;
9
11
  port?: number;
10
12
  database: string;
@@ -31,7 +33,7 @@ export interface ConnectionPool {
31
33
  queued: number;
32
34
  }
33
35
  interface ConnectionManagerInstance {
34
- getConnection(id?: string): Promise<unknown>;
36
+ getConnection(id?: string): Promise<IDatabaseAdapter>;
35
37
  releaseConnection(connectionId?: string): Promise<void>;
36
38
  closeAll(): Promise<void>;
37
39
  getPoolStats(): ConnectionPool;
@@ -58,7 +60,7 @@ export declare const ConnectionManager: Readonly<{
58
60
  /**
59
61
  * Get or create database connection
60
62
  */
61
- getConnection(id?: string): Promise<unknown>;
63
+ getConnection(id?: string): Promise<IDatabaseAdapter>;
62
64
  /**
63
65
  * Release connection back to pool (but keep persistent)
64
66
  */
@@ -97,7 +99,7 @@ export interface AuroraQueryResult {
97
99
  /**
98
100
  * Get database credentials from AWS Secrets Manager
99
101
  */
100
- export declare function getDatabaseSecret(_secretName: string): Promise<DatabaseSecret>;
102
+ export declare function getDatabaseSecret(secretName: string): Promise<DatabaseSecret>;
101
103
  /**
102
104
  * Get database credentials from environment variables
103
105
  */
@@ -1 +1 @@
1
- {"version":3,"file":"ConnectionManager.d.ts","sourceRoot":"","sources":["../../../src/orm/ConnectionManager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ConnectionManager.d.ts","sourceRoot":"","sources":["../../../src/orm/ConnectionManager.ts"],"names":[],"mappings":"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"}
@@ -1,48 +1,43 @@
1
1
  /* eslint-disable no-await-in-loop */
2
2
  /* eslint-disable @typescript-eslint/require-await */
3
3
  /**
4
- * Persistent Connection Manager for Zintrust Framework
4
+ * Persistent Connection Manager for ZinTrust Framework
5
5
  * Handles database connections across different runtime environments
6
6
  * Supports: PostgreSQL, MySQL, SQL Server with connection pooling for Lambda
7
7
  */
8
8
  import { Env } from '../config/env.js';
9
9
  import { Logger } from '../config/logger.js';
10
10
  import { ErrorFactory } from '../exceptions/ZintrustError.js';
11
+ import { D1Adapter } from './adapters/D1Adapter.js';
12
+ import { D1RemoteAdapter } from './adapters/D1RemoteAdapter.js';
13
+ import { MySQLAdapter } from './adapters/MySQLAdapter.js';
14
+ import { PostgreSQLAdapter } from './adapters/PostgreSQLAdapter.js';
15
+ import { SQLiteAdapter } from './adapters/SQLiteAdapter.js';
16
+ import { SQLServerAdapter } from './adapters/SQLServerAdapter.js';
17
+ import { DatabaseAdapterRegistry } from './DatabaseAdapterRegistry.js';
11
18
  let instance;
12
19
  /**
13
20
  * Close a specific connection
14
21
  */
15
22
  const closeConnection = async (conn) => {
16
- if (conn !== undefined &&
17
- conn !== null &&
18
- typeof conn === 'object' &&
19
- 'close' in conn &&
20
- typeof conn.close === 'function') {
21
- await conn.close();
23
+ if (isDatabaseAdapter(conn)) {
24
+ await conn.disconnect();
22
25
  }
23
26
  };
24
27
  /**
25
28
  * Test if connection is still alive
26
29
  */
27
- const testConnection = async (config, _conn) => {
30
+ const testConnection = async (_config, conn) => {
31
+ if (!isDatabaseAdapter(conn))
32
+ return false;
33
+ if (!conn.isConnected())
34
+ return false;
28
35
  try {
29
- if (config.adapter === 'postgresql' || config.adapter === 'mysql') {
30
- // SELECT 1 for PostgreSQL/MySQL
31
- await new Promise((resolve, reject) => {
32
- const timeout = globalThis.setTimeout(() => reject(ErrorFactory.createConnectionError('Connection test timeout')), 5000);
33
- try {
34
- // In real implementation, query the connection
35
- resolve(true);
36
- }
37
- finally {
38
- clearTimeout(timeout);
39
- }
40
- });
41
- }
36
+ await conn.ping();
42
37
  return true;
43
38
  }
44
39
  catch (error) {
45
- ErrorFactory.createConnectionError('Connection test failed:', error);
40
+ Logger.warn('Connection health check failed', error);
46
41
  return false;
47
42
  }
48
43
  };
@@ -50,45 +45,141 @@ const testConnection = async (config, _conn) => {
50
45
  * Update connection usage metrics
51
46
  */
52
47
  const updateConnectionUsage = (connectionPool, id) => {
53
- const entry = connectionPool.find((c) => c.id === id);
48
+ const entry = connectionPool.get(id); // O(1) lookup instead of O(n) find
54
49
  if (entry !== undefined) {
55
50
  entry.lastUsedAt = Date.now();
56
51
  entry.queryCount++;
57
52
  entry.isActive = true;
58
53
  }
59
54
  };
55
+ const isDatabaseAdapter = (value) => {
56
+ if (typeof value !== 'object' || value === null)
57
+ return false;
58
+ const candidate = value;
59
+ return (typeof candidate.connect === 'function' &&
60
+ typeof candidate.disconnect === 'function' &&
61
+ typeof candidate.ping === 'function' &&
62
+ typeof candidate.isConnected === 'function');
63
+ };
64
+ const createAdapterFromConfig = (config) => {
65
+ if (config.adapter === 'aurora-data-api') {
66
+ throw ErrorFactory.createConfigError('Aurora Data API connections should be created via getAuroraDataApiConnection()');
67
+ }
68
+ const driver = config.adapter;
69
+ const adapterConfig = {
70
+ driver,
71
+ database: config.database,
72
+ host: config.host,
73
+ port: config.port,
74
+ username: config.username,
75
+ password: config.password,
76
+ };
77
+ const registered = DatabaseAdapterRegistry.get(driver);
78
+ if (registered !== undefined) {
79
+ return registered(adapterConfig);
80
+ }
81
+ switch (driver) {
82
+ case 'postgresql':
83
+ return PostgreSQLAdapter.create(adapterConfig);
84
+ case 'mysql':
85
+ return MySQLAdapter.create(adapterConfig);
86
+ case 'sqlserver':
87
+ return SQLServerAdapter.create(adapterConfig);
88
+ case 'd1':
89
+ return D1Adapter.create(adapterConfig);
90
+ case 'd1-remote':
91
+ return D1RemoteAdapter.create(adapterConfig);
92
+ case 'sqlite':
93
+ default:
94
+ return SQLiteAdapter.create(adapterConfig);
95
+ }
96
+ };
60
97
  /**
61
98
  * Create new database connection
62
99
  */
63
100
  const createConnection = async (config, id) => {
64
101
  Logger.info(`Creating ${config.adapter} connection (${id}) to ${config.host}:${config.port}`);
65
- // Connection creation would be adapter-specific
66
- // This is a placeholder for the actual implementation
67
- return {
68
- id,
69
- adapter: config.adapter,
70
- query: async (_sql, _params) => {
71
- throw ErrorFactory.createDatabaseError(`Query execution not implemented for ${config.adapter}`);
72
- },
73
- close: async () => {
74
- Logger.info(`Connection ${id} closed`);
75
- },
76
- };
102
+ if (config.adapter === 'aurora-data-api') {
103
+ throw ErrorFactory.createConfigError('Aurora Data API connections should be created via getAuroraDataApiConnection()');
104
+ }
105
+ const adapter = createAdapterFromConfig(config);
106
+ await adapter.connect();
107
+ return adapter;
77
108
  };
78
109
  /**
79
110
  * Create Aurora Data API connection
80
111
  */
81
- const createAuroraDataApiConnection = () => ({
82
- execute: async (_sql, _params) => {
83
- // Call Aurora Data API via AWS SDK
84
- // Requires proper IAM permissions
85
- throw ErrorFactory.createConfigError('Aurora Data API not implemented yet');
86
- },
87
- batch: async (_statements) => {
88
- // Execute batch statements
89
- throw ErrorFactory.createConfigError('Aurora Data API batch not implemented yet');
90
- },
91
- });
112
+ function isMissingEsmPackage(error, packageName) {
113
+ if (typeof error !== 'object' || error === null)
114
+ return false;
115
+ const maybe = error;
116
+ const code = typeof maybe.code === 'string' ? maybe.code : '';
117
+ const message = typeof maybe.message === 'string' ? maybe.message : '';
118
+ if (code === 'ERR_MODULE_NOT_FOUND' && message.length === 0)
119
+ return true;
120
+ if (code === 'ERR_MODULE_NOT_FOUND' && message.includes(`'${packageName}'`))
121
+ return true;
122
+ if (message.includes(`Cannot find package '${packageName}'`))
123
+ return true;
124
+ return false;
125
+ }
126
+ async function importOptionalModule(modulePath) {
127
+ return import(modulePath);
128
+ }
129
+ const loadClientRdsDataModule = async () => {
130
+ try {
131
+ return (await importOptionalModule('@zintrust/client-rds-data'));
132
+ }
133
+ catch (error) {
134
+ if (isMissingEsmPackage(error, '@zintrust/client-rds-data')) {
135
+ throw ErrorFactory.createConfigError("Aurora Data API requires '@zintrust/client-rds-data' (install the package to enable AWS Data API support).");
136
+ }
137
+ throw ErrorFactory.createTryCatchError('Failed to load @zintrust/client-rds-data', {
138
+ cause: error,
139
+ });
140
+ }
141
+ };
142
+ const createAuroraDataApiConnection = () => {
143
+ const getClient = async () => {
144
+ const mod = await loadClientRdsDataModule();
145
+ return mod.getRdsDataClient(Env.AWS_REGION);
146
+ };
147
+ const resourceArn = Env.get('AURORA_RESOURCE_ARN');
148
+ const secretArn = Env.get('AURORA_SECRET_ARN');
149
+ const database = Env.get('AURORA_DATABASE', Env.DB_DATABASE);
150
+ const assertConfig = () => {
151
+ if (resourceArn.length === 0 || secretArn.length === 0) {
152
+ throw ErrorFactory.createConfigError('Aurora Data API requires AURORA_RESOURCE_ARN and AURORA_SECRET_ARN env vars');
153
+ }
154
+ };
155
+ const executeStatement = async (sql, params) => {
156
+ assertConfig();
157
+ const client = await getClient();
158
+ const input = {
159
+ resourceArn,
160
+ secretArn,
161
+ database,
162
+ sql,
163
+ parameters: (params ?? []).map((value) => ({ value: { stringValue: String(value) } })),
164
+ };
165
+ const response = (await client.executeStatement(input));
166
+ return {
167
+ numberOfRecordsUpdated: response.numberOfRecordsUpdated ?? 0,
168
+ records: response.records ?? [],
169
+ };
170
+ };
171
+ return {
172
+ execute: executeStatement,
173
+ batch: async (statements) => {
174
+ const results = [];
175
+ for (const statement of statements) {
176
+ const result = await executeStatement(statement.sql, statement.params);
177
+ results.push(result);
178
+ }
179
+ return results;
180
+ },
181
+ };
182
+ };
92
183
  /**
93
184
  * Get healthy existing connection if available
94
185
  */
@@ -101,60 +192,62 @@ const getHealthyExistingConnection = async (config, state, id) => {
101
192
  return conn;
102
193
  }
103
194
  state.connections.delete(id);
104
- state.connectionPool = state.connectionPool.filter((c) => c.id !== id);
195
+ state.connectionPool.delete(id); // O(1) instead of O(n) filter
105
196
  return null;
106
197
  };
107
198
  /**
108
199
  * Find an idle connection in the pool
109
200
  */
110
201
  const findIdleConnection = (state) => {
111
- const idleConnections = state.connectionPool.filter((c) => !c.isActive);
112
- if (idleConnections.length === 0)
202
+ let lruEntry = null;
203
+ let lruTime = Date.now();
204
+ // Iterate through Map values to find least recently used idle connection
205
+ for (const poolEntry of state.connectionPool.values()) {
206
+ if (!poolEntry.isActive && poolEntry.lastUsedAt < lruTime) {
207
+ lruTime = poolEntry.lastUsedAt;
208
+ lruEntry = poolEntry;
209
+ }
210
+ }
211
+ if (lruEntry === null)
113
212
  return null;
114
- const lru = idleConnections.reduce((prev, current) => (prev.lastUsedAt < current.lastUsedAt ? prev : current), idleConnections[0]);
115
- updateConnectionUsage(state.connectionPool, lru.id);
116
- return state.connections.get(lru.id);
213
+ updateConnectionUsage(state.connectionPool, lruEntry.id);
214
+ const conn = state.connections.get(lruEntry.id);
215
+ return conn ?? null;
117
216
  };
118
217
  /**
119
218
  * Wait for a connection to become available
120
219
  */
121
220
  const waitForIdleConnection = async (state) => {
122
221
  return new Promise((resolve, reject) => {
123
- let settled = false;
124
222
  let timeoutId;
125
- const checkInterval = setInterval(() => {
126
- const idle = state.connectionPool.find((c) => !c.isActive);
127
- if (idle !== undefined) {
128
- if (settled)
129
- return;
130
- settled = true;
131
- cleanup();
132
- updateConnectionUsage(state.connectionPool, idle.id);
133
- resolve(state.connections.get(idle.id));
134
- }
135
- }, 100);
136
223
  const cleanup = () => {
137
- clearInterval(checkInterval);
138
224
  if (timeoutId !== undefined) {
139
- clearTimeout(timeoutId);
225
+ globalThis.clearTimeout(timeoutId);
140
226
  timeoutId = undefined;
141
227
  }
142
228
  };
143
- // Node: allow process to exit; other runtimes may not support unref()
144
- if (isUnrefableTimer(checkInterval)) {
145
- checkInterval.unref();
146
- }
147
- // eslint-disable-next-line no-restricted-syntax
148
- timeoutId = setTimeout(() => {
149
- if (settled)
150
- return;
151
- settled = true;
229
+ const waiter = {
230
+ resolve: (conn) => {
231
+ cleanup();
232
+ resolve(conn);
233
+ },
234
+ reject: (err) => {
235
+ cleanup();
236
+ reject(err);
237
+ },
238
+ timeoutId,
239
+ cleanup,
240
+ };
241
+ timeoutId = globalThis.setTimeout(() => {
242
+ state.waiters = state.waiters.filter((entry) => entry !== waiter);
152
243
  cleanup();
153
244
  reject(ErrorFactory.createConnectionError('Connection pool exhausted - timeout waiting for available connection'));
154
245
  }, 30000);
246
+ waiter.timeoutId = timeoutId;
155
247
  if (isUnrefableTimer(timeoutId)) {
156
248
  timeoutId.unref();
157
249
  }
250
+ state.waiters.push(waiter);
158
251
  });
159
252
  };
160
253
  function isUnrefableTimer(value) {
@@ -181,19 +274,22 @@ const startIdleConnectionCleanup = (state, idleTimeout) => {
181
274
  state.cleanupInterval = setInterval(() => {
182
275
  const now = Date.now();
183
276
  const toRemove = [];
184
- for (const poolEntry of state.connectionPool) {
277
+ for (const [id, poolEntry] of state.connectionPool.entries()) {
185
278
  if (!poolEntry.isActive && now - poolEntry.lastUsedAt > idleTimeout) {
186
- toRemove.push(poolEntry.id);
279
+ toRemove.push(id);
187
280
  }
188
281
  }
189
282
  for (const id of toRemove) {
190
283
  const conn = state.connections.get(id);
191
284
  closeConnection(conn).catch((err) => Logger.error(`Failed to close idle connection ${id}:`, err));
192
285
  state.connections.delete(id);
193
- state.connectionPool = state.connectionPool.filter((c) => c.id !== id);
286
+ state.connectionPool.delete(id); // O(1) instead of O(n) filter
194
287
  Logger.info(`Removed idle connection: ${id}`);
195
288
  }
196
289
  }, 300000); // Every 5 minutes
290
+ if (isUnrefableTimer(state.cleanupInterval)) {
291
+ state.cleanupInterval.unref();
292
+ }
197
293
  };
198
294
  /**
199
295
  * Create and register a new connection
@@ -201,7 +297,8 @@ const startIdleConnectionCleanup = (state, idleTimeout) => {
201
297
  const createNewConnection = async (config, state, id) => {
202
298
  const connection = await createConnection(config, id);
203
299
  state.connections.set(id, connection);
204
- state.connectionPool.push({
300
+ state.connectionPool.set(id, {
301
+ // O(1) instead of O(n) push
205
302
  id,
206
303
  adapter: config.adapter,
207
304
  createdAt: Date.now(),
@@ -219,6 +316,15 @@ const closeAllConnections = async (state) => {
219
316
  clearInterval(state.cleanupInterval);
220
317
  state.cleanupInterval = undefined;
221
318
  }
319
+ if (state.waiters.length > 0) {
320
+ const err = ErrorFactory.createConnectionError('Connection manager shutting down');
321
+ for (const waiter of state.waiters) {
322
+ if (waiter.timeoutId !== undefined)
323
+ clearTimeout(waiter.timeoutId);
324
+ waiter.reject(err);
325
+ }
326
+ state.waiters = [];
327
+ }
222
328
  for (const [id, conn] of state.connections.entries()) {
223
329
  try {
224
330
  await closeConnection(conn);
@@ -228,19 +334,28 @@ const closeAllConnections = async (state) => {
228
334
  }
229
335
  }
230
336
  state.connections.clear();
231
- state.connectionPool = [];
337
+ state.connectionPool.clear(); // Use Map.clear() instead of array reset
232
338
  };
233
339
  /**
234
340
  * Get connection pool statistics
235
341
  */
236
342
  const getPoolStatistics = (state) => {
237
- const active = state.connectionPool.filter((c) => c.isActive).length;
238
- const idle = state.connectionPool.filter((c) => !c.isActive).length;
343
+ let active = 0;
344
+ let idle = 0;
345
+ // Iterate through Map values instead of filtering array
346
+ for (const poolEntry of state.connectionPool.values()) {
347
+ if (poolEntry.isActive) {
348
+ active++;
349
+ }
350
+ else {
351
+ idle++;
352
+ }
353
+ }
239
354
  return {
240
- total: state.connectionPool.length,
355
+ total: state.connectionPool.size, // Use Map.size instead of array length
241
356
  active,
242
357
  idle,
243
- queued: 0,
358
+ queued: state.waiters.length,
244
359
  };
245
360
  };
246
361
  /**
@@ -254,7 +369,8 @@ const ConnectionManagerImpl = {
254
369
  create(config) {
255
370
  const state = {
256
371
  connections: new Map(),
257
- connectionPool: [],
372
+ connectionPool: new Map(), // Changed from Array to Map
373
+ waiters: [],
258
374
  };
259
375
  const maxConnections = config.maxConnections ?? 10;
260
376
  const idleTimeout = config.idleTimeout ?? 900000; // 15 minutes
@@ -268,7 +384,8 @@ const ConnectionManagerImpl = {
268
384
  const existing = await getHealthyExistingConnection(config, state, id);
269
385
  if (existing !== null)
270
386
  return existing;
271
- if (state.connectionPool.length < maxConnections) {
387
+ if (state.connectionPool.size < maxConnections) {
388
+ // Use Map.size instead of array length
272
389
  return createNewConnection(config, state, id);
273
390
  }
274
391
  return getOrReuseConnection(state);
@@ -277,11 +394,24 @@ const ConnectionManagerImpl = {
277
394
  * Release connection back to pool (but keep persistent)
278
395
  */
279
396
  async releaseConnection(connectionId = 'default') {
280
- const poolEntry = state.connectionPool.find((c) => c.id === connectionId);
281
- if (poolEntry !== undefined) {
282
- poolEntry.isActive = false;
283
- poolEntry.lastUsedAt = Date.now();
397
+ const poolEntry = state.connectionPool.get(connectionId); // O(1) instead of O(n) find
398
+ if (poolEntry === undefined)
399
+ return;
400
+ poolEntry.isActive = false;
401
+ poolEntry.lastUsedAt = Date.now();
402
+ if (state.waiters.length === 0)
403
+ return;
404
+ const waiter = state.waiters.shift();
405
+ if (waiter === undefined)
406
+ return;
407
+ waiter.cleanup();
408
+ const conn = state.connections.get(connectionId);
409
+ if (conn === undefined) {
410
+ waiter.reject(ErrorFactory.createConnectionError('Released connection not found'));
411
+ return;
284
412
  }
413
+ updateConnectionUsage(state.connectionPool, connectionId);
414
+ waiter.resolve(conn);
285
415
  },
286
416
  /**
287
417
  * Close all connections (graceful shutdown)
@@ -341,6 +471,7 @@ export const ConnectionManager = Object.freeze({
341
471
  if (instance !== undefined) {
342
472
  try {
343
473
  await instance.closeAll();
474
+ instance = undefined;
344
475
  }
345
476
  catch (err) {
346
477
  Logger.error('Error while shutting down ConnectionManager:', err);
@@ -387,9 +518,34 @@ export const ConnectionManager = Object.freeze({
387
518
  /**
388
519
  * Get database credentials from AWS Secrets Manager
389
520
  */
390
- export async function getDatabaseSecret(_secretName) {
391
- // Would use AWS SDK to fetch from Secrets Manager
392
- throw ErrorFactory.createConfigError('Secrets Manager integration not implemented');
521
+ export async function getDatabaseSecret(secretName) {
522
+ try {
523
+ const mod = await loadClientRdsDataModule();
524
+ const client = await mod.getSecretsManagerClient(Env.AWS_REGION);
525
+ const response = await client.getSecretValue(secretName);
526
+ const secretString = response.SecretString;
527
+ if (secretString === undefined || secretString === null || secretString.trim().length === 0) {
528
+ throw ErrorFactory.createConfigError('Secrets Manager returned an empty secret');
529
+ }
530
+ const parsed = JSON.parse(secretString);
531
+ if (parsed.username === undefined ||
532
+ parsed.password === undefined ||
533
+ parsed.host === undefined ||
534
+ parsed.port === undefined ||
535
+ parsed.database === undefined) {
536
+ throw ErrorFactory.createConfigError('Secrets Manager secret is missing required fields');
537
+ }
538
+ return {
539
+ username: parsed.username,
540
+ password: parsed.password,
541
+ host: parsed.host,
542
+ port: Number(parsed.port),
543
+ database: parsed.database,
544
+ };
545
+ }
546
+ catch (error) {
547
+ throw ErrorFactory.createTryCatchError('Failed to fetch database secret', { cause: error });
548
+ }
393
549
  }
394
550
  /**
395
551
  * Get database credentials from environment variables
@@ -2,6 +2,7 @@
2
2
  * Database Manager
3
3
  * Central database connection management and query execution
4
4
  */
5
+ import type { SupportedDriver } from '../migrations/enum';
5
6
  import type { DatabaseConfig, IDatabaseAdapter, QueryResult } from './DatabaseAdapter';
6
7
  import type { IQueryBuilder } from './QueryBuilder';
7
8
  export interface IDatabase {
@@ -18,7 +19,7 @@ export interface IDatabase {
18
19
  offBeforeQuery(handler: (query: string, params: unknown[]) => void): void;
19
20
  offAfterQuery(handler: (query: string, params: unknown[], duration: number) => void): void;
20
21
  getAdapterInstance(isRead?: boolean): IDatabaseAdapter;
21
- getType(): string;
22
+ getType(): SupportedDriver;
22
23
  getConfig(): DatabaseConfig;
23
24
  dispose(): void;
24
25
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Database.d.ts","sourceRoot":"","sources":["../../../src/orm/Database.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAaH,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAE1F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGvD,MAAM,WAAW,SAAS;IACxB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACzB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,WAAW,IAAI,OAAO,CAAC;IACvB,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,OAAO,EAAE,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IACjF,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,OAAO,EAAE,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAClF,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,OAAO,EAAE,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IACrF,WAAW,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACpE,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,CAAC;IACnC,aAAa,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,IAAI,GAAG,IAAI,CAAC;IACzE,YAAY,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IAC1F,cAAc,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,IAAI,GAAG,IAAI,CAAC;IAC1E,aAAa,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IAC3F,kBAAkB,CAAC,MAAM,CAAC,EAAE,OAAO,GAAG,gBAAgB,CAAC;IACvD,OAAO,IAAI,MAAM,CAAC;IAClB,SAAS,IAAI,cAAc,CAAC;IAC5B,OAAO,IAAI,IAAI,CAAC;CACjB;AA0YD,eAAO,MAAM,QAAQ;IACnB;;OAEG;oBACa,cAAc,GAAG,SAAS;EAI1C,CAAC;AAIH,eAAO,MAAM,oBAAoB,GAC/B,kBAAkB,EAClB,uBAA0B,KACzB,OAAO,CAAC,UAAU,CAAC,OAAO,WAAW,CAAC,CAMxC,CAAC;AAEF,wBAAgB,WAAW,CAAC,MAAM,CAAC,EAAE,cAAc,EAAE,UAAU,SAAY,GAAG,SAAS,CAgBtF;AAED,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAWnD"}
1
+ {"version":3,"file":"Database.d.ts","sourceRoot":"","sources":["../../../src/orm/Database.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAQxD,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAE1F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGvD,MAAM,WAAW,SAAS;IACxB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACzB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,WAAW,IAAI,OAAO,CAAC;IACvB,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,OAAO,EAAE,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IACjF,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,OAAO,EAAE,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAClF,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,OAAO,EAAE,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IACrF,WAAW,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACpE,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,CAAC;IACnC,aAAa,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,IAAI,GAAG,IAAI,CAAC;IACzE,YAAY,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IAC1F,cAAc,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,IAAI,GAAG,IAAI,CAAC;IAC1E,aAAa,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IAC3F,kBAAkB,CAAC,MAAM,CAAC,EAAE,OAAO,GAAG,gBAAgB,CAAC;IACvD,OAAO,IAAI,eAAe,CAAC;IAC3B,SAAS,IAAI,cAAc,CAAC;IAC5B,OAAO,IAAI,IAAI,CAAC;CACjB;AA0YD,eAAO,MAAM,QAAQ;IACnB;;OAEG;oBACa,cAAc,GAAG,SAAS;EAI1C,CAAC;AAIH,eAAO,MAAM,oBAAoB,GAC/B,kBAAkB,EAClB,uBAA0B,KACzB,OAAO,CAAC,UAAU,CAAC,OAAO,WAAW,CAAC,CAMxC,CAAC;AAEF,wBAAgB,WAAW,CAAC,MAAM,CAAC,EAAE,cAAc,EAAE,UAAU,SAAY,GAAG,SAAS,CAgBtF;AAED,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAWnD"}
@@ -2,6 +2,7 @@
2
2
  * Database Adapter Interface
3
3
  * Defines contract for different database implementations
4
4
  */
5
+ import type { SupportedDriver } from '../migrations/enum';
5
6
  /**
6
7
  * Minimal D1 Database interface for type safety
7
8
  */
@@ -23,7 +24,7 @@ export interface ID1Database {
23
24
  }
24
25
  export interface DatabaseConfig {
25
26
  d1?: ID1Database;
26
- driver: 'sqlite' | 'postgresql' | 'mysql' | 'sqlserver' | 'd1' | 'd1-remote';
27
+ driver: SupportedDriver;
27
28
  database?: string;
28
29
  host?: string;
29
30
  port?: number;
@@ -86,7 +87,7 @@ export interface IDatabaseAdapter {
86
87
  /**
87
88
  * Get database type
88
89
  */
89
- getType(): string;
90
+ getType(): SupportedDriver;
90
91
  /**
91
92
  * Check connection status
92
93
  */
@@ -1 +1 @@
1
- {"version":3,"file":"DatabaseAdapter.d.ts","sourceRoot":"","sources":["../../../src/orm/DatabaseAdapter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"DatabaseAdapter.d.ts","sourceRoot":"","sources":["../../../src/orm/DatabaseAdapter.ts"],"names":[],"mappings":"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"}
@@ -20,9 +20,26 @@ export const BaseAdapter = Object.freeze({
20
20
  if (typeof value === 'boolean') {
21
21
  return value ? '1' : '0';
22
22
  }
23
+ // Support BigInt explicitly to avoid JSON.stringify errors and driver issues
24
+ if (typeof value === 'bigint') {
25
+ return String(value);
26
+ }
27
+ // Dates should be passed as ISO strings
28
+ if (value instanceof Date) {
29
+ return `'${value.toISOString()}'`;
30
+ }
23
31
  if (typeof value === 'number') {
24
32
  return String(value);
25
33
  }
34
+ // Buffer / Uint8Array -> base64 string
35
+ // Some DB adapters expect binary types; returning base64-encoded string is a safe default
36
+ // and prevents JSON.stringify(BigInt) errors when objects include BigInt.
37
+ if (typeof Buffer !== 'undefined' && Buffer.isBuffer(value)) {
38
+ return `'${value.toString('base64')}'`;
39
+ }
40
+ if (value instanceof Uint8Array) {
41
+ return `'${Buffer.from(value).toString('base64')}'`;
42
+ }
26
43
  // For objects, convert to JSON string representation
27
44
  return `'${JSON.stringify(value).replaceAll("'", "''")}'`;
28
45
  },