@grupodiariodaregiao/bunstone 0.7.1 → 0.7.2

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.
@@ -1,38 +1,36 @@
1
1
  import { SQL } from "bun";
2
- export type SqlPoolOptions = {
3
- /** Maximum connections in the pool. Bun default: 10 */
4
- max?: number;
5
- /**
6
- * Seconds before closing idle pool connections. Bun default: 0 (no limit).
7
- * For MariaDB/MySQL, set below the server `wait_timeout` (often 28800 = 8h).
8
- */
9
- idleTimeout?: number;
2
+ type Provider = "postgresql" | "mysql" | "sqlite";
3
+ type BunSqlPoolOptions = Pick<SQL.PostgresOrMySQLOptions, "max" | "maxLifetime" | "connectionTimeout" | "idleTimeout" | "connection" | "tls" | "prepare" | "bigint" | "onconnect" | "onclose" | "path">;
4
+ type BunSqliteClientOptions = Pick<SQL.SQLiteOptions, "readonly" | "create" | "safeIntegers" | "strict">;
5
+ /** Options forwarded by Bunstone to the underlying Bun.SQL client. */
6
+ export type BunSqlClientOptions = Partial<BunSqlPoolOptions & BunSqliteClientOptions>;
7
+ /**
8
+ * Options accepted by {@link SqlModule.register}.
9
+ * Only Bunstone-supported settings are allowed.
10
+ */
11
+ export type SqlModuleOptions = BunSqlClientOptions & {
10
12
  /**
11
- * Max connection lifetime in seconds. Bun default: 0 (no limit).
12
- * Forces periodic reconnection before the server drops stale sockets.
13
+ * Timezone used for date/time interpretation on the database connection.
14
+ * Mapped to driver `connection` settings when not provided explicitly.
15
+ * Defaults to `UTC`.
13
16
  */
14
- maxLifetime?: number;
15
- /** Seconds to wait when opening a new connection. Bun default: 30 */
16
- connectionTimeout?: number;
17
+ timezone?: string;
17
18
  };
18
- export type SqlConnectionOptions = SqlPoolOptions & {
19
+ export type SqlConnectionDetails = {
19
20
  host: string;
20
21
  port: number;
21
22
  username: string;
22
23
  password: string;
23
24
  database: string;
24
- provider: "postgresql" | "mysql" | "sqlite";
25
- /**
26
- * Timezone used for date/time interpretation on the database connection.
27
- * Defaults to 'UTC' to ensure consistent, offset-free date handling.
28
- * Set to 'local' to use the process timezone, or any valid tz identifier.
29
- */
30
- timezone?: string;
25
+ provider: Provider;
31
26
  };
32
- export type SqlRegisterOptions = SqlPoolOptions & {
33
- timezone?: string;
34
- };
35
- type Provider = "postgresql" | "mysql" | "sqlite";
27
+ export type ConnectionOptions = SqlConnectionDetails & SqlModuleOptions;
28
+ /** @deprecated Use {@link ConnectionOptions} */
29
+ export type SqlConnectionOptions = ConnectionOptions;
30
+ /** @deprecated Use {@link SqlModuleOptions} */
31
+ export type SqlRegisterOptions = SqlModuleOptions;
32
+ /** Pool-related subset of {@link SqlModuleOptions}. */
33
+ export type SqlPoolOptions = Pick<SqlModuleOptions, "max" | "maxLifetime" | "connectionTimeout" | "idleTimeout">;
36
34
  export declare class SqlService {
37
35
  query<T = any>(query: string, params?: any[]): Promise<T[]>;
38
36
  transaction(queries: Array<{
@@ -48,9 +46,8 @@ export declare class SqlService {
48
46
  export declare class SqlModule {
49
47
  private static sqlInstance;
50
48
  private static provider;
51
- static register(connection: SqlConnectionOptions): typeof SqlModule;
52
- static register(connection: string, timezone?: string): typeof SqlModule;
53
- static register(connection: string, options: SqlRegisterOptions): typeof SqlModule;
49
+ static register(connection: ConnectionOptions): typeof SqlModule;
50
+ static register(connection: string, options?: SqlModuleOptions | string): typeof SqlModule;
54
51
  static getSqlInstance(): SQL;
55
52
  static getProvider(): Provider | undefined;
56
53
  }
@@ -75,10 +75,12 @@ export declare class CqrsError extends BunstoneError {
75
75
  * Codes:
76
76
  * - `BNS-DB-001` – SQL instance not initialised
77
77
  * - `BNS-DB-002` – query / transaction execution failed
78
+ * - `BNS-DB-003` – invalid SqlModule configuration option
78
79
  */
79
80
  export declare class DatabaseError extends BunstoneError {
80
- constructor(message: string, code?: "BNS-DB-001" | "BNS-DB-002", suggestion?: string, context?: Record<string, unknown>, cause?: Error);
81
+ constructor(message: string, code?: "BNS-DB-001" | "BNS-DB-002" | "BNS-DB-003", suggestion?: string, context?: Record<string, unknown>, cause?: Error);
81
82
  static notInitialized(): DatabaseError;
83
+ static invalidConfig(invalidKeys: string[], allowedKeys: readonly string[]): DatabaseError;
82
84
  }
83
85
  /**
84
86
  * Thrown when BullMQ operations fail.
@@ -43,6 +43,68 @@ OR using a connection string:
43
43
  export class AppModule {}
44
44
  ```
45
45
 
46
+ ### Connection options
47
+
48
+ You can pass a second argument with pool and client settings. Bunstone forwards only the supported options to [Bun.SQL](https://bun.sh/docs/api/sql):
49
+
50
+ ```typescript
51
+ @Module({
52
+ imports: [
53
+ SqlModule.register("mysql://user:pass@host:3306/db", {
54
+ maxLifetime: 25200,
55
+ connectionTimeout: 30,
56
+ max: 10,
57
+ timezone: "UTC",
58
+ }),
59
+ ],
60
+ })
61
+ export class AppModule {}
62
+ ```
63
+
64
+ The same options can be combined with the object-style registration:
65
+
66
+ ```typescript
67
+ SqlModule.register({
68
+ provider: "postgresql",
69
+ host: "localhost",
70
+ port: 5432,
71
+ username: "user",
72
+ password: "password",
73
+ database: "my_db",
74
+ max: 20,
75
+ idleTimeout: 30,
76
+ });
77
+ ```
78
+
79
+ For backward compatibility, the second argument may still be a timezone string:
80
+
81
+ ```typescript
82
+ SqlModule.register("mysql://user:pass@host/db", "UTC");
83
+ ```
84
+
85
+ #### Supported options (`SqlModuleOptions`)
86
+
87
+ | Option | Description |
88
+ |---|---|
89
+ | `timezone` | Bunstone helper for date/time handling. Defaults to `UTC`. Mapped to driver `connection` settings. |
90
+ | `max` | Maximum connections in the pool |
91
+ | `maxLifetime` | Maximum connection lifetime in seconds |
92
+ | `connectionTimeout` | Timeout when establishing a connection (seconds) |
93
+ | `idleTimeout` | Close idle connections after N seconds |
94
+ | `connection` | Driver-specific runtime settings (e.g. PostgreSQL `TimeZone`) |
95
+ | `tls` | TLS/SSL configuration |
96
+ | `prepare` | Enable automatic prepared statements |
97
+ | `bigint` | Return out-of-range integers as `BigInt` |
98
+ | `onconnect` | Callback when a connection attempt completes |
99
+ | `onclose` | Callback when a connection closes |
100
+ | `path` | Unix domain socket path |
101
+ | `readonly` | SQLite read-only mode |
102
+ | `create` | SQLite create-if-missing behavior |
103
+ | `safeIntegers` | SQLite safe integer handling |
104
+ | `strict` | SQLite strict mode |
105
+
106
+ Only the options listed above are accepted. Invalid keys are rejected by TypeScript and also throw `DatabaseError` (`BNS-DB-003`) at runtime.
107
+
46
108
  ## Usage
47
109
 
48
110
  Once registered, the `SqlService` is globally available. You can inject it into any controller or provider without needing to import `SqlModule` into subsequent modules.
@@ -43,6 +43,68 @@ OU usando uma string de conexão:
43
43
  export class AppModule {}
44
44
  ```
45
45
 
46
+ ### Opções de conexão
47
+
48
+ Você pode passar um segundo argumento com configurações de pool e do client. O Bunstone repassa apenas as opções suportadas para o [Bun.SQL](https://bun.sh/docs/api/sql):
49
+
50
+ ```typescript
51
+ @Module({
52
+ imports: [
53
+ SqlModule.register("mysql://user:pass@host:3306/db", {
54
+ maxLifetime: 25200,
55
+ connectionTimeout: 30,
56
+ max: 10,
57
+ timezone: "UTC",
58
+ }),
59
+ ],
60
+ })
61
+ export class AppModule {}
62
+ ```
63
+
64
+ As mesmas opções podem ser usadas no registro via objeto:
65
+
66
+ ```typescript
67
+ SqlModule.register({
68
+ provider: "postgresql",
69
+ host: "localhost",
70
+ port: 5432,
71
+ username: "user",
72
+ password: "password",
73
+ database: "my_db",
74
+ max: 20,
75
+ idleTimeout: 30,
76
+ });
77
+ ```
78
+
79
+ Por compatibilidade, o segundo argumento ainda pode ser uma string de timezone:
80
+
81
+ ```typescript
82
+ SqlModule.register("mysql://user:pass@host/db", "UTC");
83
+ ```
84
+
85
+ #### Opções suportadas (`SqlModuleOptions`)
86
+
87
+ | Opção | Descrição |
88
+ |---|---|
89
+ | `timezone` | Helper do Bunstone para datas/horas. Padrão: `UTC`. Mapeado para `connection` do driver. |
90
+ | `max` | Máximo de conexões no pool |
91
+ | `maxLifetime` | Tempo máximo de vida da conexão em segundos |
92
+ | `connectionTimeout` | Timeout ao estabelecer conexão (segundos) |
93
+ | `idleTimeout` | Fecha conexões ociosas após N segundos |
94
+ | `connection` | Configurações runtime do driver (ex.: `TimeZone` no PostgreSQL) |
95
+ | `tls` | Configuração TLS/SSL |
96
+ | `prepare` | Habilita prepared statements automáticos |
97
+ | `bigint` | Retorna inteiros fora do range como `BigInt` |
98
+ | `onconnect` | Callback ao concluir tentativa de conexão |
99
+ | `onclose` | Callback ao fechar conexão |
100
+ | `path` | Caminho do Unix domain socket |
101
+ | `readonly` | Modo somente leitura (SQLite) |
102
+ | `create` | Comportamento de criação do arquivo (SQLite) |
103
+ | `safeIntegers` | Tratamento seguro de inteiros (SQLite) |
104
+ | `strict` | Modo strict (SQLite) |
105
+
106
+ Somente as opções listadas acima são aceitas. Chaves inválidas são rejeitadas pelo TypeScript e também lançam `DatabaseError` (`BNS-DB-003`) em runtime.
107
+
46
108
  ## Uso
47
109
 
48
110
  Depois de registrado, o `SqlService` fica disponível globalmente. Você pode injetá-lo em qualquer controller ou provider sem precisar importar o `SqlModule` nos módulos subsequentes.
@@ -9,49 +9,134 @@ import { DatabaseError } from "../errors";
9
9
  import { Injectable } from "../injectable";
10
10
  import { Module } from "../module";
11
11
 
12
- export type SqlPoolOptions = {
13
- /** Maximum connections in the pool. Bun default: 10 */
14
- max?: number;
15
- /**
16
- * Seconds before closing idle pool connections. Bun default: 0 (no limit).
17
- * For MariaDB/MySQL, set below the server `wait_timeout` (often 28800 = 8h).
18
- */
19
- idleTimeout?: number;
12
+ type Provider = "postgresql" | "mysql" | "sqlite";
13
+
14
+ type BunSqlPoolOptions = Pick<
15
+ SQL.PostgresOrMySQLOptions,
16
+ | "max"
17
+ | "maxLifetime"
18
+ | "connectionTimeout"
19
+ | "idleTimeout"
20
+ | "connection"
21
+ | "tls"
22
+ | "prepare"
23
+ | "bigint"
24
+ | "onconnect"
25
+ | "onclose"
26
+ | "path"
27
+ >;
28
+
29
+ type BunSqliteClientOptions = Pick<
30
+ SQL.SQLiteOptions,
31
+ "readonly" | "create" | "safeIntegers" | "strict"
32
+ >;
33
+
34
+ /** Options forwarded by Bunstone to the underlying Bun.SQL client. */
35
+ export type BunSqlClientOptions = Partial<
36
+ BunSqlPoolOptions & BunSqliteClientOptions
37
+ >;
38
+
39
+ /**
40
+ * Options accepted by {@link SqlModule.register}.
41
+ * Only Bunstone-supported settings are allowed.
42
+ */
43
+ export type SqlModuleOptions = BunSqlClientOptions & {
20
44
  /**
21
- * Max connection lifetime in seconds. Bun default: 0 (no limit).
22
- * Forces periodic reconnection before the server drops stale sockets.
45
+ * Timezone used for date/time interpretation on the database connection.
46
+ * Mapped to driver `connection` settings when not provided explicitly.
47
+ * Defaults to `UTC`.
23
48
  */
24
- maxLifetime?: number;
25
- /** Seconds to wait when opening a new connection. Bun default: 30 */
26
- connectionTimeout?: number;
49
+ timezone?: string;
27
50
  };
28
51
 
29
- export type SqlConnectionOptions = SqlPoolOptions & {
52
+ export type SqlConnectionDetails = {
30
53
  host: string;
31
54
  port: number;
32
55
  username: string;
33
56
  password: string;
34
57
  database: string;
35
- provider: "postgresql" | "mysql" | "sqlite";
36
- /**
37
- * Timezone used for date/time interpretation on the database connection.
38
- * Defaults to 'UTC' to ensure consistent, offset-free date handling.
39
- * Set to 'local' to use the process timezone, or any valid tz identifier.
40
- */
41
- timezone?: string;
58
+ provider: Provider;
42
59
  };
43
60
 
44
- export type SqlRegisterOptions = SqlPoolOptions & {
45
- timezone?: string;
46
- };
47
-
48
- type Provider = "postgresql" | "mysql" | "sqlite";
61
+ export type ConnectionOptions = SqlConnectionDetails & SqlModuleOptions;
62
+
63
+ /** @deprecated Use {@link ConnectionOptions} */
64
+ export type SqlConnectionOptions = ConnectionOptions;
65
+
66
+ /** @deprecated Use {@link SqlModuleOptions} */
67
+ export type SqlRegisterOptions = SqlModuleOptions;
68
+
69
+ /** Pool-related subset of {@link SqlModuleOptions}. */
70
+ export type SqlPoolOptions = Pick<
71
+ SqlModuleOptions,
72
+ "max" | "maxLifetime" | "connectionTimeout" | "idleTimeout"
73
+ >;
74
+
75
+ type SqlClientInitOptions = Omit<
76
+ SqlModuleOptions,
77
+ "url" | "filename" | "timezone"
78
+ >;
79
+
80
+ const SQL_MODULE_OPTION_KEYS = [
81
+ "timezone",
82
+ "max",
83
+ "maxLifetime",
84
+ "connectionTimeout",
85
+ "idleTimeout",
86
+ "connection",
87
+ "tls",
88
+ "prepare",
89
+ "bigint",
90
+ "onconnect",
91
+ "onclose",
92
+ "path",
93
+ "readonly",
94
+ "create",
95
+ "safeIntegers",
96
+ "strict",
97
+ ] as const satisfies readonly (keyof SqlModuleOptions)[];
98
+
99
+ const SQL_CONNECTION_DETAIL_KEYS = [
100
+ "host",
101
+ "port",
102
+ "username",
103
+ "password",
104
+ "database",
105
+ "provider",
106
+ ] as const satisfies readonly (keyof SqlConnectionDetails)[];
49
107
 
50
108
  const CONNECTION_CLOSED_CODES = new Set([
51
109
  "ERR_MYSQL_CONNECTION_CLOSED",
52
110
  "ERR_POSTGRES_CONNECTION_CLOSED",
53
111
  ]);
54
112
 
113
+ function assertOnlyAllowedKeys(
114
+ source: Record<string, unknown>,
115
+ allowedKeys: readonly string[],
116
+ ): void {
117
+ const invalidKeys = Object.keys(source).filter(
118
+ (key) => !allowedKeys.includes(key),
119
+ );
120
+
121
+ if (invalidKeys.length > 0) {
122
+ throw DatabaseError.invalidConfig(invalidKeys, allowedKeys);
123
+ }
124
+ }
125
+
126
+ function pickSqlModuleOptions(
127
+ source: Record<string, unknown>,
128
+ ): SqlModuleOptions {
129
+ assertOnlyAllowedKeys(source, SQL_MODULE_OPTION_KEYS);
130
+
131
+ const picked = {} as SqlModuleOptions;
132
+ for (const key of SQL_MODULE_OPTION_KEYS) {
133
+ if (key in source) {
134
+ (picked as Record<string, unknown>)[key] = source[key];
135
+ }
136
+ }
137
+ return picked;
138
+ }
139
+
55
140
  function detectProvider(url: string): Provider {
56
141
  if (url.startsWith("mysql://") || url.startsWith("mysql2://")) {
57
142
  return "mysql";
@@ -71,34 +156,106 @@ function detectProvider(url: string): Provider {
71
156
  function buildConnectionConfig(
72
157
  provider: Provider,
73
158
  timezone: string,
74
- ): Record<string, string | boolean | number> | undefined {
159
+ ): NonNullable<SQL.PostgresOrMySQLOptions["connection"]> | undefined {
75
160
  if (provider === "postgresql") {
76
161
  return { TimeZone: timezone };
77
162
  }
78
163
  if (provider === "mysql") {
79
- // Normalise to MySQL's expected offset format ('+00:00') or named zone
80
164
  const tz = timezone.toLowerCase() === "utc" ? "+00:00" : timezone;
81
165
  return { time_zone: tz };
82
166
  }
83
167
  return undefined;
84
168
  }
85
169
 
86
- function pickPoolOptions(
87
- source: SqlPoolOptions | undefined,
88
- ): SqlPoolOptions | undefined {
89
- if (!source) {
90
- return undefined;
170
+ function normalizeRegisterOptions(
171
+ options?: SqlModuleOptions | string,
172
+ ): SqlModuleOptions {
173
+ if (typeof options === "string") {
174
+ return { timezone: options };
175
+ }
176
+ if (!options) {
177
+ return {};
178
+ }
179
+
180
+ return pickSqlModuleOptions(options as Record<string, unknown>);
181
+ }
182
+
183
+ function buildSqlClientOptions(
184
+ provider: Provider,
185
+ timezone: string,
186
+ options: SqlModuleOptions,
187
+ ): SqlClientInitOptions {
188
+ const { timezone: _timezone, connection: userConnection, ...rest } = options;
189
+ const driverConnectionConfig = buildConnectionConfig(provider, timezone);
190
+ const connection = {
191
+ ...driverConnectionConfig,
192
+ ...userConnection,
193
+ };
194
+
195
+ return {
196
+ ...rest,
197
+ ...(Object.keys(connection).length > 0 && { connection }),
198
+ };
199
+ }
200
+
201
+ function resolveConnectionUrl(connection: string | ConnectionOptions): string {
202
+ if (typeof connection === "string") {
203
+ return connection;
91
204
  }
92
205
 
93
- const pool: SqlPoolOptions = {};
94
- if (source.max !== undefined) pool.max = source.max;
95
- if (source.idleTimeout !== undefined) pool.idleTimeout = source.idleTimeout;
96
- if (source.maxLifetime !== undefined) pool.maxLifetime = source.maxLifetime;
97
- if (source.connectionTimeout !== undefined) {
98
- pool.connectionTimeout = source.connectionTimeout;
206
+ return `${connection.provider}://${connection.username}:${connection.password}@${connection.host}:${connection.port}/${connection.database}`;
207
+ }
208
+
209
+ function resolveProvider(connection: string | ConnectionOptions): Provider {
210
+ return typeof connection === "string"
211
+ ? detectProvider(connection)
212
+ : connection.provider;
213
+ }
214
+
215
+ function resolveTimezone(
216
+ connection: string | ConnectionOptions,
217
+ options: SqlModuleOptions,
218
+ ): string {
219
+ if (options.timezone) {
220
+ return options.timezone;
99
221
  }
100
222
 
101
- return Object.keys(pool).length > 0 ? pool : undefined;
223
+ if (typeof connection === "object" && connection.timezone) {
224
+ return connection.timezone;
225
+ }
226
+
227
+ return "UTC";
228
+ }
229
+
230
+ function resolveRegisterOptions(
231
+ connection: string | ConnectionOptions,
232
+ options?: SqlModuleOptions | string,
233
+ ): SqlModuleOptions {
234
+ const normalized = normalizeRegisterOptions(options);
235
+
236
+ if (typeof connection !== "object") {
237
+ return normalized;
238
+ }
239
+
240
+ assertOnlyAllowedKeys(
241
+ connection as Record<string, unknown>,
242
+ [...SQL_CONNECTION_DETAIL_KEYS, ...SQL_MODULE_OPTION_KEYS],
243
+ );
244
+
245
+ const {
246
+ host: _host,
247
+ port: _port,
248
+ username: _username,
249
+ password: _password,
250
+ database: _database,
251
+ provider: _provider,
252
+ ...connectionSqlOptions
253
+ } = connection;
254
+
255
+ return {
256
+ ...pickSqlModuleOptions(connectionSqlOptions as Record<string, unknown>),
257
+ ...normalized,
258
+ };
102
259
  }
103
260
 
104
261
  function isConnectionClosedError(err: unknown): boolean {
@@ -138,10 +295,7 @@ export class SqlService {
138
295
  return withConnectionRetry(() => this.executeBulkInsert(table, values));
139
296
  }
140
297
 
141
- private async executeQuery<T>(
142
- query: string,
143
- params?: any[],
144
- ): Promise<T[]> {
298
+ private async executeQuery<T>(query: string, params?: any[]): Promise<T[]> {
145
299
  const sql = this.getSqlInstance();
146
300
  const tracer = trace.getTracer("bunstone.db");
147
301
  const operation = detectOperation(query);
@@ -209,7 +363,10 @@ export class SqlService {
209
363
  );
210
364
  }
211
365
 
212
- private async executeBulkInsert<T>(table: string, values: T[]): Promise<void> {
366
+ private async executeBulkInsert<T>(
367
+ table: string,
368
+ values: T[],
369
+ ): Promise<void> {
213
370
  const sql = this.getSqlInstance();
214
371
  const tracer = trace.getTracer("bunstone.db");
215
372
  const span = tracer.startSpan("db.INSERT", {
@@ -257,51 +414,31 @@ export class SqlModule {
257
414
  private static sqlInstance: SQL;
258
415
  private static provider: Provider | undefined;
259
416
 
260
- static register(connection: SqlConnectionOptions): typeof SqlModule;
261
- static register(connection: string, timezone?: string): typeof SqlModule;
417
+ static register(connection: ConnectionOptions): typeof SqlModule;
262
418
  static register(
263
419
  connection: string,
264
- options: SqlRegisterOptions,
420
+ options?: SqlModuleOptions | string,
265
421
  ): typeof SqlModule;
266
422
  static register(
267
- connection: string | SqlConnectionOptions,
268
- second?: string | SqlRegisterOptions,
423
+ connection: string | ConnectionOptions,
424
+ options?: SqlModuleOptions | string,
269
425
  ) {
270
- const url =
271
- typeof connection === "string"
272
- ? connection
273
- : `${connection.provider}://${connection.username}:${connection.password}@${connection.host}:${connection.port}/${connection.database}`;
274
-
275
- const provider =
276
- typeof connection === "string"
277
- ? detectProvider(connection)
278
- : connection.provider;
426
+ const resolvedOptions = resolveRegisterOptions(connection, options);
427
+ const url = resolveConnectionUrl(connection);
428
+ const provider = resolveProvider(connection);
429
+ const timezone = resolveTimezone(connection, resolvedOptions);
430
+ const sqlOptions = buildSqlClientOptions(
431
+ provider,
432
+ timezone,
433
+ resolvedOptions,
434
+ );
279
435
 
280
436
  SqlModule.provider = provider;
281
437
 
282
- let timezone = "UTC";
283
- let poolOptions: SqlPoolOptions | undefined;
284
-
285
- if (typeof connection === "string") {
286
- if (typeof second === "string") {
287
- timezone = second;
288
- } else if (second) {
289
- timezone = second.timezone ?? "UTC";
290
- poolOptions = pickPoolOptions(second);
291
- }
292
- } else {
293
- timezone = connection.timezone ?? "UTC";
294
- poolOptions = pickPoolOptions(connection);
295
- }
296
-
297
- const connectionConfig = buildConnectionConfig(provider, timezone);
298
- const pool = poolOptions ?? {};
299
-
300
438
  SqlModule.sqlInstance = new SQL({
301
439
  url,
302
- ...pool,
303
- ...(connectionConfig && { connection: connectionConfig }),
304
- });
440
+ ...sqlOptions,
441
+ } as SQL.Options);
305
442
 
306
443
  return SqlModule;
307
444
  }
@@ -337,10 +474,6 @@ function detectOperation(query: string): string {
337
474
  return "QUERY";
338
475
  }
339
476
 
340
- /**
341
- * Strips parameter values from SQL for safe inclusion in telemetry.
342
- * Keeps the query structure readable without leaking user data.
343
- */
344
477
  function sanitizeSql(query: string): string {
345
478
  return query
346
479
  .replace(/'[^']*'/g, "'?'")
@@ -244,11 +244,12 @@ export class CqrsError extends BunstoneError {
244
244
  * Codes:
245
245
  * - `BNS-DB-001` – SQL instance not initialised
246
246
  * - `BNS-DB-002` – query / transaction execution failed
247
+ * - `BNS-DB-003` – invalid SqlModule configuration option
247
248
  */
248
249
  export class DatabaseError extends BunstoneError {
249
250
  constructor(
250
251
  message: string,
251
- code: "BNS-DB-001" | "BNS-DB-002" = "BNS-DB-001",
252
+ code: "BNS-DB-001" | "BNS-DB-002" | "BNS-DB-003" = "BNS-DB-001",
252
253
  suggestion?: string,
253
254
  context?: Record<string, unknown>,
254
255
  cause?: Error,
@@ -266,6 +267,18 @@ export class DatabaseError extends BunstoneError {
266
267
  ].join("\n "),
267
268
  );
268
269
  }
270
+
271
+ static invalidConfig(
272
+ invalidKeys: string[],
273
+ allowedKeys: readonly string[],
274
+ ): DatabaseError {
275
+ return new DatabaseError(
276
+ `Invalid SqlModule option(s): ${invalidKeys.join(", ")}.`,
277
+ "BNS-DB-003",
278
+ `Use only supported options: ${allowedKeys.join(", ")}.`,
279
+ { invalidKeys, allowedKeys },
280
+ );
281
+ }
269
282
  }
270
283
 
271
284
  // ─── BullMQ ───────────────────────────────────────────────────────────────────
package/package.json CHANGED
@@ -13,7 +13,7 @@
13
13
  "types": "./dist/*.d.ts"
14
14
  }
15
15
  },
16
- "version": "0.7.1",
16
+ "version": "0.7.2",
17
17
  "homepage": "https://bunstone.diario.one/",
18
18
  "repository": {
19
19
  "url": "https://github.com/diariodaregiao/bunstone.git",