relq 1.0.111 → 1.0.113

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.
@@ -257,15 +257,24 @@ class PgBase extends relq_base_1.RelqBase {
257
257
  return;
258
258
  this.poolErrorHandler = (err) => {
259
259
  const errorCode = err.code;
260
- const recoverableErrors = ['ETIMEDOUT', 'ECONNRESET', '57P02'];
261
- if (!recoverableErrors.includes(errorCode)) {
262
- throw err;
260
+ if (isPoolRecoverableError(errorCode)) {
261
+ const logLevel = this.config.logLevel ?? 'info';
262
+ if (logLevel !== 'silent') {
263
+ console.warn('[Relq Pool] Recoverable connection error (pool will auto-recover):', {
264
+ code: errorCode,
265
+ message: err.message,
266
+ action: 'Connection removed from pool, will be replaced on next query'
267
+ });
268
+ }
269
+ return;
270
+ }
271
+ const logLevel = this.config.logLevel ?? 'info';
272
+ if (logLevel !== 'silent') {
273
+ console.error('[Relq Pool] Pool error:', {
274
+ code: errorCode,
275
+ message: err.message,
276
+ });
263
277
  }
264
- console.warn('[Relq Pool] Recoverable connection error (pool will auto-recover):', {
265
- code: errorCode,
266
- message: err.message,
267
- action: 'Connection removed from pool, will be replaced on next query'
268
- });
269
278
  };
270
279
  this.poolConnectHandler = () => { };
271
280
  this.poolRemoveHandler = () => { };
@@ -349,3 +358,22 @@ class PgBase extends relq_base_1.RelqBase {
349
358
  }
350
359
  }
351
360
  exports.PgBase = PgBase;
361
+ const POOL_RECOVERABLE_NETWORK_CODES = new Set([
362
+ 'ECONNRESET', 'ECONNREFUSED', 'ENOTFOUND', 'ESERVFAIL',
363
+ 'ETIMEDOUT', 'EPIPE', 'EAI_AGAIN', 'EHOSTUNREACH',
364
+ 'ECONNABORTED', 'ENETUNREACH', 'ENETRESET',
365
+ 'CONNECTION_LOST', 'PROTOCOL_CONNECTION_LOST',
366
+ ]);
367
+ const POOL_RECOVERABLE_PG_CODES = new Set([
368
+ '57P01',
369
+ '57P02',
370
+ '57P03',
371
+ '08006',
372
+ '08001',
373
+ '08004',
374
+ ]);
375
+ function isPoolRecoverableError(code) {
376
+ if (!code)
377
+ return true;
378
+ return POOL_RECOVERABLE_NETWORK_CODES.has(code) || POOL_RECOVERABLE_PG_CODES.has(code);
379
+ }
@@ -14,6 +14,7 @@ class RelqBase {
14
14
  config;
15
15
  schema;
16
16
  emitter = new node_events_1.EventEmitter();
17
+ _defaultErrorHandler = () => { };
17
18
  columnMappings = new Map();
18
19
  initialized = false;
19
20
  initPromise;
@@ -21,6 +22,7 @@ class RelqBase {
21
22
  constructor(schema, config) {
22
23
  this.config = config;
23
24
  this.schema = schema;
25
+ this.emitter.on('error', this._defaultErrorHandler);
24
26
  if (schema) {
25
27
  const log = config.logLevel === 'debug'
26
28
  ? (...args) => (0, helpers_1.debugLog)(config, ...args)
@@ -243,15 +245,26 @@ class RelqBase {
243
245
  }
244
246
  }
245
247
  exports.RelqBase = RelqBase;
246
- const TRANSIENT_CODES = new Set([
248
+ const TRANSIENT_NETWORK_CODES = new Set([
247
249
  'ECONNRESET', 'ECONNREFUSED', 'ENOTFOUND', 'ESERVFAIL',
248
250
  'ETIMEDOUT', 'EPIPE', 'EAI_AGAIN', 'EHOSTUNREACH',
249
251
  'CONNECTION_LOST', 'PROTOCOL_CONNECTION_LOST',
250
252
  ]);
253
+ const TRANSIENT_PG_CODES = new Set([
254
+ '40P01',
255
+ '40001',
256
+ '08006',
257
+ '08001',
258
+ '08004',
259
+ '57P01',
260
+ '57P03',
261
+ ]);
251
262
  function isTransientError(error) {
252
- if (TRANSIENT_CODES.has(error.code))
263
+ if (TRANSIENT_NETWORK_CODES.has(error.code))
264
+ return true;
265
+ if (error.cause && TRANSIENT_NETWORK_CODES.has(error.cause.code))
253
266
  return true;
254
- if (error.cause && TRANSIENT_CODES.has(error.cause.code))
267
+ if (TRANSIENT_PG_CODES.has(error.code))
255
268
  return true;
256
269
  return false;
257
270
  }
@@ -312,7 +312,15 @@ function wrapError(error, context) {
312
312
  function parsePostgresError(error, sql) {
313
313
  const message = error.message || 'Database error';
314
314
  const code = error.code;
315
- if (code === 'ECONNREFUSED' || code === 'ENOTFOUND' || code === 'ETIMEDOUT') {
315
+ if (isNetworkErrorCode(code)) {
316
+ return new RelqConnectionError(message, {
317
+ cause: error,
318
+ code,
319
+ host: error.hostname || error.address,
320
+ port: error.port
321
+ });
322
+ }
323
+ if (code === '57P01' || code === '57P03' || code === '08006' || code === '08001' || code === '08004') {
316
324
  return new RelqConnectionError(message, {
317
325
  cause: error,
318
326
  code,
@@ -331,3 +339,11 @@ function parsePostgresError(error, sql) {
331
339
  hint: error.hint
332
340
  });
333
341
  }
342
+ const NETWORK_ERROR_CODES = new Set([
343
+ 'ECONNREFUSED', 'ECONNRESET', 'ENOTFOUND', 'ESERVFAIL',
344
+ 'ETIMEDOUT', 'EPIPE', 'EAI_AGAIN', 'EHOSTUNREACH',
345
+ 'CONNECTION_LOST', 'PROTOCOL_CONNECTION_LOST',
346
+ ]);
347
+ function isNetworkErrorCode(code) {
348
+ return !!code && NETWORK_ERROR_CODES.has(code);
349
+ }
@@ -220,15 +220,24 @@ export class PgBase extends RelqBase {
220
220
  return;
221
221
  this.poolErrorHandler = (err) => {
222
222
  const errorCode = err.code;
223
- const recoverableErrors = ['ETIMEDOUT', 'ECONNRESET', '57P02'];
224
- if (!recoverableErrors.includes(errorCode)) {
225
- throw err;
223
+ if (isPoolRecoverableError(errorCode)) {
224
+ const logLevel = this.config.logLevel ?? 'info';
225
+ if (logLevel !== 'silent') {
226
+ console.warn('[Relq Pool] Recoverable connection error (pool will auto-recover):', {
227
+ code: errorCode,
228
+ message: err.message,
229
+ action: 'Connection removed from pool, will be replaced on next query'
230
+ });
231
+ }
232
+ return;
233
+ }
234
+ const logLevel = this.config.logLevel ?? 'info';
235
+ if (logLevel !== 'silent') {
236
+ console.error('[Relq Pool] Pool error:', {
237
+ code: errorCode,
238
+ message: err.message,
239
+ });
226
240
  }
227
- console.warn('[Relq Pool] Recoverable connection error (pool will auto-recover):', {
228
- code: errorCode,
229
- message: err.message,
230
- action: 'Connection removed from pool, will be replaced on next query'
231
- });
232
241
  };
233
242
  this.poolConnectHandler = () => { };
234
243
  this.poolRemoveHandler = () => { };
@@ -311,3 +320,22 @@ export class PgBase extends RelqBase {
311
320
  this.emitter.emit('connect', this.client);
312
321
  }
313
322
  }
323
+ const POOL_RECOVERABLE_NETWORK_CODES = new Set([
324
+ 'ECONNRESET', 'ECONNREFUSED', 'ENOTFOUND', 'ESERVFAIL',
325
+ 'ETIMEDOUT', 'EPIPE', 'EAI_AGAIN', 'EHOSTUNREACH',
326
+ 'ECONNABORTED', 'ENETUNREACH', 'ENETRESET',
327
+ 'CONNECTION_LOST', 'PROTOCOL_CONNECTION_LOST',
328
+ ]);
329
+ const POOL_RECOVERABLE_PG_CODES = new Set([
330
+ '57P01',
331
+ '57P02',
332
+ '57P03',
333
+ '08006',
334
+ '08001',
335
+ '08004',
336
+ ]);
337
+ function isPoolRecoverableError(code) {
338
+ if (!code)
339
+ return true;
340
+ return POOL_RECOVERABLE_NETWORK_CODES.has(code) || POOL_RECOVERABLE_PG_CODES.has(code);
341
+ }
@@ -11,6 +11,7 @@ export class RelqBase {
11
11
  config;
12
12
  schema;
13
13
  emitter = new EventEmitter();
14
+ _defaultErrorHandler = () => { };
14
15
  columnMappings = new Map();
15
16
  initialized = false;
16
17
  initPromise;
@@ -18,6 +19,7 @@ export class RelqBase {
18
19
  constructor(schema, config) {
19
20
  this.config = config;
20
21
  this.schema = schema;
22
+ this.emitter.on('error', this._defaultErrorHandler);
21
23
  if (schema) {
22
24
  const log = config.logLevel === 'debug'
23
25
  ? (...args) => debugLog(config, ...args)
@@ -239,15 +241,26 @@ export class RelqBase {
239
241
  return this._isClosed;
240
242
  }
241
243
  }
242
- const TRANSIENT_CODES = new Set([
244
+ const TRANSIENT_NETWORK_CODES = new Set([
243
245
  'ECONNRESET', 'ECONNREFUSED', 'ENOTFOUND', 'ESERVFAIL',
244
246
  'ETIMEDOUT', 'EPIPE', 'EAI_AGAIN', 'EHOSTUNREACH',
245
247
  'CONNECTION_LOST', 'PROTOCOL_CONNECTION_LOST',
246
248
  ]);
249
+ const TRANSIENT_PG_CODES = new Set([
250
+ '40P01',
251
+ '40001',
252
+ '08006',
253
+ '08001',
254
+ '08004',
255
+ '57P01',
256
+ '57P03',
257
+ ]);
247
258
  function isTransientError(error) {
248
- if (TRANSIENT_CODES.has(error.code))
259
+ if (TRANSIENT_NETWORK_CODES.has(error.code))
260
+ return true;
261
+ if (error.cause && TRANSIENT_NETWORK_CODES.has(error.cause.code))
249
262
  return true;
250
- if (error.cause && TRANSIENT_CODES.has(error.cause.code))
263
+ if (TRANSIENT_PG_CODES.has(error.code))
251
264
  return true;
252
265
  return false;
253
266
  }
@@ -290,7 +290,15 @@ export function wrapError(error, context) {
290
290
  export function parsePostgresError(error, sql) {
291
291
  const message = error.message || 'Database error';
292
292
  const code = error.code;
293
- if (code === 'ECONNREFUSED' || code === 'ENOTFOUND' || code === 'ETIMEDOUT') {
293
+ if (isNetworkErrorCode(code)) {
294
+ return new RelqConnectionError(message, {
295
+ cause: error,
296
+ code,
297
+ host: error.hostname || error.address,
298
+ port: error.port
299
+ });
300
+ }
301
+ if (code === '57P01' || code === '57P03' || code === '08006' || code === '08001' || code === '08004') {
294
302
  return new RelqConnectionError(message, {
295
303
  cause: error,
296
304
  code,
@@ -309,3 +317,11 @@ export function parsePostgresError(error, sql) {
309
317
  hint: error.hint
310
318
  });
311
319
  }
320
+ const NETWORK_ERROR_CODES = new Set([
321
+ 'ECONNREFUSED', 'ECONNRESET', 'ENOTFOUND', 'ESERVFAIL',
322
+ 'ETIMEDOUT', 'EPIPE', 'EAI_AGAIN', 'EHOSTUNREACH',
323
+ 'CONNECTION_LOST', 'PROTOCOL_CONNECTION_LOST',
324
+ ]);
325
+ function isNetworkErrorCode(code) {
326
+ return !!code && NETWORK_ERROR_CODES.has(code);
327
+ }
package/dist/index.d.ts CHANGED
@@ -10023,6 +10023,7 @@ export declare abstract class RelqBase<TSchema = any> {
10023
10023
  protected config: RelqConfig;
10024
10024
  protected schema?: TSchema;
10025
10025
  protected readonly emitter: EventEmitter<any>;
10026
+ private readonly _defaultErrorHandler;
10026
10027
  protected columnMappings: ColumnMappings;
10027
10028
  protected initialized: boolean;
10028
10029
  protected initPromise?: Promise<void>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "relq",
3
- "version": "1.0.111",
3
+ "version": "1.0.113",
4
4
  "description": "The Fully-Typed PostgreSQL ORM for TypeScript",
5
5
  "author": "Olajide Mathew O. <olajide.mathew@yuniq.solutions>",
6
6
  "license": "MIT",