@venizia/ignis 0.0.9-9 → 0.0.9

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 (181) hide show
  1. package/README.md +15 -15
  2. package/dist/base/middlewares/app-error/app-error.middleware.d.ts +15 -0
  3. package/dist/base/middlewares/app-error/app-error.middleware.d.ts.map +1 -0
  4. package/dist/base/middlewares/app-error/app-error.middleware.js +81 -0
  5. package/dist/base/middlewares/app-error/app-error.middleware.js.map +1 -0
  6. package/dist/base/middlewares/app-error/database.handler.d.ts +20 -0
  7. package/dist/base/middlewares/app-error/database.handler.d.ts.map +1 -0
  8. package/dist/base/middlewares/app-error/database.handler.js +55 -0
  9. package/dist/base/middlewares/app-error/database.handler.js.map +1 -0
  10. package/dist/base/middlewares/app-error/definition.d.ts +59 -0
  11. package/dist/base/middlewares/app-error/definition.d.ts.map +1 -0
  12. package/dist/base/middlewares/app-error/definition.js +98 -0
  13. package/dist/base/middlewares/app-error/definition.js.map +1 -0
  14. package/dist/base/middlewares/app-error/index.d.ts +2 -0
  15. package/dist/base/middlewares/app-error/index.d.ts.map +1 -0
  16. package/dist/{components/auth/authorize/models/abilities → base/middlewares/app-error}/index.js +1 -2
  17. package/dist/base/middlewares/app-error/index.js.map +1 -0
  18. package/dist/base/middlewares/app-error/types.d.ts +18 -0
  19. package/dist/base/middlewares/app-error/types.d.ts.map +1 -0
  20. package/dist/base/middlewares/app-error/types.js +3 -0
  21. package/dist/base/middlewares/app-error/types.js.map +1 -0
  22. package/dist/base/middlewares/app-error/zod.handler.d.ts +28 -0
  23. package/dist/base/middlewares/app-error/zod.handler.d.ts.map +1 -0
  24. package/dist/base/middlewares/app-error/zod.handler.js +64 -0
  25. package/dist/base/middlewares/app-error/zod.handler.js.map +1 -0
  26. package/dist/base/middlewares/emoji-favicon/emoji-favicon.middleware.d.ts.map +1 -0
  27. package/dist/base/middlewares/emoji-favicon/emoji-favicon.middleware.js.map +1 -0
  28. package/dist/base/middlewares/emoji-favicon/index.d.ts +2 -0
  29. package/dist/base/middlewares/emoji-favicon/index.d.ts.map +1 -0
  30. package/dist/base/middlewares/emoji-favicon/index.js +18 -0
  31. package/dist/base/middlewares/emoji-favicon/index.js.map +1 -0
  32. package/dist/base/middlewares/index.d.ts +4 -4
  33. package/dist/base/middlewares/index.d.ts.map +1 -1
  34. package/dist/base/middlewares/index.js +4 -4
  35. package/dist/base/middlewares/index.js.map +1 -1
  36. package/dist/base/middlewares/not-found/index.d.ts +2 -0
  37. package/dist/base/middlewares/not-found/index.d.ts.map +1 -0
  38. package/dist/base/middlewares/not-found/index.js +18 -0
  39. package/dist/base/middlewares/not-found/index.js.map +1 -0
  40. package/dist/base/middlewares/{not-found.middleware.d.ts → not-found/not-found.middleware.d.ts} +0 -1
  41. package/dist/base/middlewares/not-found/not-found.middleware.d.ts.map +1 -0
  42. package/dist/base/middlewares/{not-found.middleware.js → not-found/not-found.middleware.js} +2 -3
  43. package/dist/base/middlewares/{not-found.middleware.js.map → not-found/not-found.middleware.js.map} +1 -1
  44. package/dist/base/middlewares/request-spy/index.d.ts +2 -0
  45. package/dist/base/middlewares/request-spy/index.d.ts.map +1 -0
  46. package/dist/base/middlewares/request-spy/index.js +18 -0
  47. package/dist/base/middlewares/request-spy/index.js.map +1 -0
  48. package/dist/base/middlewares/{request-spy.middleware.d.ts → request-spy/request-spy.middleware.d.ts} +1 -1
  49. package/dist/base/middlewares/request-spy/request-spy.middleware.d.ts.map +1 -0
  50. package/dist/base/middlewares/{request-spy.middleware.js → request-spy/request-spy.middleware.js} +1 -1
  51. package/dist/base/middlewares/request-spy/request-spy.middleware.js.map +1 -0
  52. package/dist/base/models/common/columns.d.ts +22 -0
  53. package/dist/base/models/common/columns.d.ts.map +1 -0
  54. package/dist/base/models/common/columns.js +43 -0
  55. package/dist/base/models/common/columns.js.map +1 -0
  56. package/dist/base/models/common/index.d.ts +1 -0
  57. package/dist/base/models/common/index.d.ts.map +1 -1
  58. package/dist/base/models/common/index.js +1 -0
  59. package/dist/base/models/common/index.js.map +1 -1
  60. package/dist/base/models/enrichers/principal.enricher.d.ts +6 -5
  61. package/dist/base/models/enrichers/principal.enricher.d.ts.map +1 -1
  62. package/dist/base/models/enrichers/principal.enricher.js +8 -3
  63. package/dist/base/models/enrichers/principal.enricher.js.map +1 -1
  64. package/dist/base/models/enrichers/tz.enricher.d.ts +9 -8
  65. package/dist/base/models/enrichers/tz.enricher.d.ts.map +1 -1
  66. package/dist/base/models/enrichers/tz.enricher.js +10 -10
  67. package/dist/base/models/enrichers/tz.enricher.js.map +1 -1
  68. package/dist/base/repositories/core/readable.d.ts.map +1 -1
  69. package/dist/base/repositories/core/readable.js +16 -4
  70. package/dist/base/repositories/core/readable.js.map +1 -1
  71. package/dist/base/repositories/core/soft-deletable.d.ts +1 -1
  72. package/dist/base/repositories/core/soft-deletable.d.ts.map +1 -1
  73. package/dist/components/auth/authorize/adapters/base-filtered.d.ts +26 -56
  74. package/dist/components/auth/authorize/adapters/base-filtered.d.ts.map +1 -1
  75. package/dist/components/auth/authorize/adapters/base-filtered.js +23 -70
  76. package/dist/components/auth/authorize/adapters/base-filtered.js.map +1 -1
  77. package/dist/components/auth/authorize/adapters/index.d.ts +2 -1
  78. package/dist/components/auth/authorize/adapters/index.d.ts.map +1 -1
  79. package/dist/components/auth/authorize/adapters/index.js +2 -1
  80. package/dist/components/auth/authorize/adapters/index.js.map +1 -1
  81. package/dist/components/auth/authorize/adapters/scoped-casbin.adapter.d.ts +138 -0
  82. package/dist/components/auth/authorize/adapters/scoped-casbin.adapter.d.ts.map +1 -0
  83. package/dist/components/auth/authorize/adapters/scoped-casbin.adapter.js +300 -0
  84. package/dist/components/auth/authorize/adapters/scoped-casbin.adapter.js.map +1 -0
  85. package/dist/components/auth/authorize/adapters/types.d.ts +31 -0
  86. package/dist/components/auth/authorize/adapters/types.d.ts.map +1 -0
  87. package/dist/components/auth/authorize/adapters/types.js +3 -0
  88. package/dist/components/auth/authorize/adapters/types.js.map +1 -0
  89. package/dist/components/auth/authorize/common/constants.d.ts +144 -8
  90. package/dist/components/auth/authorize/common/constants.d.ts.map +1 -1
  91. package/dist/components/auth/authorize/common/constants.js +171 -13
  92. package/dist/components/auth/authorize/common/constants.js.map +1 -1
  93. package/dist/components/auth/authorize/common/index.d.ts +4 -0
  94. package/dist/components/auth/authorize/common/index.d.ts.map +1 -1
  95. package/dist/components/auth/authorize/common/index.js +4 -0
  96. package/dist/components/auth/authorize/common/index.js.map +1 -1
  97. package/dist/components/auth/authorize/common/object-match.d.ts +21 -0
  98. package/dist/components/auth/authorize/common/object-match.d.ts.map +1 -0
  99. package/dist/components/auth/authorize/common/object-match.js +33 -0
  100. package/dist/components/auth/authorize/common/object-match.js.map +1 -0
  101. package/dist/components/auth/authorize/common/permission-builder.d.ts +92 -0
  102. package/dist/components/auth/authorize/common/permission-builder.d.ts.map +1 -0
  103. package/dist/components/auth/authorize/common/permission-builder.js +99 -0
  104. package/dist/components/auth/authorize/common/permission-builder.js.map +1 -0
  105. package/dist/components/auth/authorize/common/policy-builder.d.ts +183 -0
  106. package/dist/components/auth/authorize/common/policy-builder.d.ts.map +1 -0
  107. package/dist/components/auth/authorize/common/policy-builder.js +130 -0
  108. package/dist/components/auth/authorize/common/policy-builder.js.map +1 -0
  109. package/dist/components/auth/authorize/common/resolve-request-domain.d.ts +20 -0
  110. package/dist/components/auth/authorize/common/resolve-request-domain.d.ts.map +1 -0
  111. package/dist/components/auth/authorize/common/resolve-request-domain.js +59 -0
  112. package/dist/components/auth/authorize/common/resolve-request-domain.js.map +1 -0
  113. package/dist/components/auth/authorize/common/types.d.ts +70 -23
  114. package/dist/components/auth/authorize/common/types.d.ts.map +1 -1
  115. package/dist/components/auth/authorize/enforcers/casbin.enforcer.d.ts +120 -28
  116. package/dist/components/auth/authorize/enforcers/casbin.enforcer.d.ts.map +1 -1
  117. package/dist/components/auth/authorize/enforcers/casbin.enforcer.js +324 -124
  118. package/dist/components/auth/authorize/enforcers/casbin.enforcer.js.map +1 -1
  119. package/dist/components/auth/authorize/enforcers/enforcer-registry.d.ts +19 -1
  120. package/dist/components/auth/authorize/enforcers/enforcer-registry.d.ts.map +1 -1
  121. package/dist/components/auth/authorize/enforcers/enforcer-registry.js +23 -0
  122. package/dist/components/auth/authorize/enforcers/enforcer-registry.js.map +1 -1
  123. package/dist/components/auth/authorize/enforcers/index.d.ts +1 -0
  124. package/dist/components/auth/authorize/enforcers/index.d.ts.map +1 -1
  125. package/dist/components/auth/authorize/enforcers/index.js +1 -0
  126. package/dist/components/auth/authorize/enforcers/index.js.map +1 -1
  127. package/dist/components/auth/authorize/enforcers/models/index.d.ts +2 -0
  128. package/dist/components/auth/authorize/enforcers/models/index.d.ts.map +1 -0
  129. package/dist/components/auth/authorize/enforcers/models/index.js +18 -0
  130. package/dist/components/auth/authorize/enforcers/models/index.js.map +1 -0
  131. package/dist/components/auth/authorize/enforcers/models/rbac-domain.model.d.ts +32 -0
  132. package/dist/components/auth/authorize/enforcers/models/rbac-domain.model.d.ts.map +1 -0
  133. package/dist/components/auth/authorize/enforcers/models/rbac-domain.model.js +54 -0
  134. package/dist/components/auth/authorize/enforcers/models/rbac-domain.model.js.map +1 -0
  135. package/dist/components/auth/authorize/models/index.d.ts +0 -1
  136. package/dist/components/auth/authorize/models/index.d.ts.map +1 -1
  137. package/dist/components/auth/authorize/models/index.js +0 -1
  138. package/dist/components/auth/authorize/models/index.js.map +1 -1
  139. package/dist/components/auth/authorize/providers/authorization.provider.d.ts.map +1 -1
  140. package/dist/components/auth/authorize/providers/authorization.provider.js +12 -0
  141. package/dist/components/auth/authorize/providers/authorization.provider.js.map +1 -1
  142. package/dist/components/auth/models/entities/permission.model.d.ts +2 -0
  143. package/dist/components/auth/models/entities/permission.model.d.ts.map +1 -1
  144. package/dist/components/auth/models/entities/permission.model.js +4 -0
  145. package/dist/components/auth/models/entities/permission.model.js.map +1 -1
  146. package/dist/components/auth/models/entities/user.model.d.ts +16 -2
  147. package/dist/components/auth/models/entities/user.model.d.ts.map +1 -1
  148. package/dist/components/auth/models/entities/user.model.js +3 -2
  149. package/dist/components/auth/models/entities/user.model.js.map +1 -1
  150. package/dist/components/mail/helpers/executors/internal-queue-executor.helper.d.ts.map +1 -1
  151. package/dist/components/mail/helpers/executors/internal-queue-executor.helper.js +1 -1
  152. package/dist/components/mail/helpers/executors/internal-queue-executor.helper.js.map +1 -1
  153. package/dist/components/static-asset/models/base.model.d.ts +24 -16
  154. package/dist/components/static-asset/models/base.model.d.ts.map +1 -1
  155. package/package.json +6 -5
  156. package/dist/base/middlewares/app-error.middleware.d.ts +0 -8
  157. package/dist/base/middlewares/app-error.middleware.d.ts.map +0 -1
  158. package/dist/base/middlewares/app-error.middleware.js +0 -138
  159. package/dist/base/middlewares/app-error.middleware.js.map +0 -1
  160. package/dist/base/middlewares/emoji-favicon.middleware.d.ts.map +0 -1
  161. package/dist/base/middlewares/emoji-favicon.middleware.js.map +0 -1
  162. package/dist/base/middlewares/not-found.middleware.d.ts.map +0 -1
  163. package/dist/base/middlewares/request-spy.middleware.d.ts.map +0 -1
  164. package/dist/base/middlewares/request-spy.middleware.js.map +0 -1
  165. package/dist/components/auth/authorize/adapters/drizzle-casbin.d.ts +0 -46
  166. package/dist/components/auth/authorize/adapters/drizzle-casbin.d.ts.map +0 -1
  167. package/dist/components/auth/authorize/adapters/drizzle-casbin.js +0 -104
  168. package/dist/components/auth/authorize/adapters/drizzle-casbin.js.map +0 -1
  169. package/dist/components/auth/authorize/models/abilities/index.d.ts +0 -3
  170. package/dist/components/auth/authorize/models/abilities/index.d.ts.map +0 -1
  171. package/dist/components/auth/authorize/models/abilities/index.js.map +0 -1
  172. package/dist/components/auth/authorize/models/abilities/string-action.model.d.ts +0 -14
  173. package/dist/components/auth/authorize/models/abilities/string-action.model.d.ts.map +0 -1
  174. package/dist/components/auth/authorize/models/abilities/string-action.model.js +0 -23
  175. package/dist/components/auth/authorize/models/abilities/string-action.model.js.map +0 -1
  176. package/dist/components/auth/authorize/models/abilities/string-resource.model.d.ts +0 -13
  177. package/dist/components/auth/authorize/models/abilities/string-resource.model.d.ts.map +0 -1
  178. package/dist/components/auth/authorize/models/abilities/string-resource.model.js +0 -19
  179. package/dist/components/auth/authorize/models/abilities/string-resource.model.js.map +0 -1
  180. /package/dist/base/middlewares/{emoji-favicon.middleware.d.ts → emoji-favicon/emoji-favicon.middleware.d.ts} +0 -0
  181. /package/dist/base/middlewares/{emoji-favicon.middleware.js → emoji-favicon/emoji-favicon.middleware.js} +0 -0
package/README.md CHANGED
@@ -10,7 +10,7 @@
10
10
  [![Hono](https://img.shields.io/badge/Hono-4.x-E36002.svg?style=flat-square&logo=hono&logoColor=white)](https://hono.dev/)
11
11
  [![Drizzle ORM](https://img.shields.io/badge/Drizzle_ORM-0.45-C5F74F.svg?style=flat-square)](https://orm.drizzle.team/)
12
12
 
13
- Ignis brings together the structured, enterprise development experience of **LoopBack 4** with the blazing speed and simplicity of **Hono**, giving you the best of both worlds: decorator-based DI, repository pattern, DataSource abstraction, component system, boot conventions running on Hono's ~140k req/s engine with Drizzle ORM's type-safe SQL.
13
+ IGNIS brings together the structured, enterprise development experience of **LoopBack 4** with the blazing speed and simplicity of **Hono**, giving you the best of both worlds: decorator-based DI, repository pattern, DataSource abstraction, component system, boot conventions - running on Hono's ~140k req/s engine with Drizzle ORM's type-safe SQL.
14
14
 
15
15
  [Installation](#installation) • [Quick Start](#quick-start) • [API Reference](#controllers) • [Documentation](https://venizia-ai.github.io/ignis)
16
16
 
@@ -34,7 +34,7 @@ Ignis brings together the structured, enterprise development experience of **Loo
34
34
  ```typescript
35
35
  import {
36
36
  BaseApplication, // Your app extends this
37
- BaseController, // Controllers extend this
37
+ BaseRestController, // Controllers extend this
38
38
  DefaultCRUDRepository, // Repositories extend this
39
39
  BaseEntity, // Models extend this
40
40
  BaseDataSource, // DataSources extend this
@@ -200,14 +200,14 @@ export class UserRepository extends PersistableRepository<typeof User.schema> {
200
200
  ```typescript
201
201
  // controllers/user.controller.ts
202
202
  import {
203
- BaseController, controller, get, post,
203
+ BaseRestController, controller, get, post,
204
204
  inject, jsonContent, jsonResponse, HTTP, TRouteContext,
205
205
  } from '@venizia/ignis';
206
206
  import { z } from '@hono/zod-openapi';
207
207
  import { UserRepository } from '../repositories/user.repository';
208
208
 
209
209
  @controller({ path: '/users' })
210
- export class UserController extends BaseController {
210
+ export class UserController extends BaseRestController {
211
211
  constructor(
212
212
  @inject({ key: 'repositories.UserRepository' }) private userRepo: UserRepository,
213
213
  ) {
@@ -276,7 +276,7 @@ export class Application extends BaseApplication {
276
276
  }
277
277
 
278
278
  getAppInfo(): IApplicationInfo {
279
- return { name: 'My App', version: '1.0.0', description: 'My Ignis application' };
279
+ return { name: 'My App', version: '1.0.0', description: 'My IGNIS application' };
280
280
  }
281
281
 
282
282
  staticConfigure() {}
@@ -437,7 +437,7 @@ Runtime-aware: uses `hono/bun` `serveStatic` on Bun, `@hono/node-server/serve-st
437
437
 
438
438
  ### Runtime Detection
439
439
 
440
- Ignis auto-detects the runtime and starts the server accordingly:
440
+ IGNIS auto-detects the runtime and starts the server accordingly:
441
441
 
442
442
  ```typescript
443
443
  // Bun (default)
@@ -499,9 +499,9 @@ interface IApplicationInfo {
499
499
 
500
500
  ## Controllers
501
501
 
502
- ### BaseController
502
+ ### BaseRestController
503
503
 
504
- All controllers extend `BaseController`, which provides:
504
+ All controllers extend `BaseRestController`, which provides:
505
505
 
506
506
  - An `OpenAPIHono` router instance
507
507
  - Route registration methods (`defineRoute`, `bindRoute`, `defineJSXRoute`)
@@ -510,7 +510,7 @@ All controllers extend `BaseController`, which provides:
510
510
  - Zod-based request validation with automatic 422 error responses
511
511
 
512
512
  ```typescript
513
- abstract class BaseController extends AbstractController {
513
+ abstract class BaseRestController extends AbstractController {
514
514
  // Register routes -- override this method
515
515
  abstract binding(): ValueOrPromise<void>;
516
516
 
@@ -536,7 +536,7 @@ Use `@get`, `@post`, `@put`, `@patch`, `@del`, or the generic `@api` decorators.
536
536
 
537
537
  ```typescript
538
538
  @controller({ path: '/products' })
539
- class ProductController extends BaseController {
539
+ class ProductController extends BaseRestController {
540
540
  constructor(
541
541
  @inject({ key: 'repositories.ProductRepository' }) private productRepo: ProductRepository,
542
542
  @inject({ key: 'services.InventoryService' }) private inventoryService: InventoryService,
@@ -2167,7 +2167,7 @@ const UserController = ControllerFactory.defineCrudController({
2167
2167
 
2168
2168
  // Route-level (via decorators)
2169
2169
  @controller({ path: '/products' })
2170
- class ProductController extends BaseController {
2170
+ class ProductController extends BaseRestController {
2171
2171
  @get({
2172
2172
  configs: {
2173
2173
  path: '/',
@@ -2573,7 +2573,7 @@ export class UserService extends BaseService {
2573
2573
 
2574
2574
  // controllers/user.controller.ts
2575
2575
  @controller({ path: '/users' })
2576
- export class UserController extends BaseController {
2576
+ export class UserController extends BaseRestController {
2577
2577
  constructor(
2578
2578
  @inject({ key: 'services.UserService' }) private userService: UserService,
2579
2579
  @inject({ key: 'repositories.UserRepository' }) private userRepo: UserRepository,
@@ -2783,9 +2783,9 @@ describe('UserController', () => {
2783
2783
 
2784
2784
  ## Documentation
2785
2785
 
2786
- - [Ignis Repository](https://github.com/VENIZIA-AI/ignis)
2787
- - [Getting Started](https://github.com/VENIZIA-AI/ignis/blob/main/packages/docs/wiki/get-started/index.md)
2788
- - [Core Concepts](https://github.com/VENIZIA-AI/ignis/blob/main/packages/docs/wiki/get-started/core-concepts/application.md)
2786
+ - [IGNIS Repository](https://github.com/VENIZIA-AI/ignis)
2787
+ - [Getting Started](https://github.com/VENIZIA-AI/ignis/blob/main/docs/wiki/content/get-started/index.md)
2788
+ - [Core Concepts](https://github.com/VENIZIA-AI/ignis/blob/main/docs/wiki/content/get-started/core-concepts/application.md)
2789
2789
  - [Examples](https://github.com/VENIZIA-AI/ignis/tree/main/examples/vert)
2790
2790
 
2791
2791
  ---
@@ -0,0 +1,15 @@
1
+ import { Logger } from '@venizia/ignis-helpers';
2
+ import { ErrorHandler } from 'hono/types';
3
+ /**
4
+ * Application error handler (Hono `onError`). Routes each error to the right shape:
5
+ * - ZodError → 422 via {@link formatZodError}
6
+ * - DB client error (class 22/23/44) → 400 via {@link isDatabaseClientError}
7
+ * - Transient DB conflict (40001/40P01) → 409 via {@link isRetryableDatabaseError}
8
+ * - Intentional domain error (`getError`) → its own status/message
9
+ * - Anything else → 500 (generic message in production)
10
+ */
11
+ export declare const appErrorHandler: (opts: {
12
+ logger: Logger;
13
+ rootKey?: string;
14
+ }) => ErrorHandler;
15
+ //# sourceMappingURL=app-error.middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-error.middleware.d.ts","sourceRoot":"","sources":["../../../../src/base/middlewares/app-error/app-error.middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,MAAM,EAAE,MAAM,wBAAwB,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAQ1C;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,GAAI,MAAM;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,iBAqFzE,CAAC"}
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.appErrorHandler = void 0;
4
+ const ignis_helpers_1 = require("@venizia/ignis-helpers");
5
+ const request_spy_1 = require("../request-spy");
6
+ const database_handler_1 = require("./database.handler");
7
+ const definition_1 = require("./definition");
8
+ const zod_handler_1 = require("./zod.handler");
9
+ const DEFAULT_INTERNAL_ERROR_MESSAGE = 'Internal Server Error';
10
+ /**
11
+ * Application error handler (Hono `onError`). Routes each error to the right shape:
12
+ * - ZodError → 422 via {@link formatZodError}
13
+ * - DB client error (class 22/23/44) → 400 via {@link isDatabaseClientError}
14
+ * - Transient DB conflict (40001/40P01) → 409 via {@link isRetryableDatabaseError}
15
+ * - Intentional domain error (`getError`) → its own status/message
16
+ * - Anything else → 500 (generic message in production)
17
+ */
18
+ const appErrorHandler = (opts) => {
19
+ const { logger = console, rootKey = null } = opts;
20
+ const mw = async (error, context) => {
21
+ const requestId = context.get(request_spy_1.RequestSpyMiddleware.REQUEST_ID_KEY);
22
+ logger.error('[onError][%s] REQUEST ERROR | path: %s | method: %s | url: %s | Error: %j', requestId, context.req.path, context.req.method, context.req.url, error);
23
+ const { NODE_ENV } = process.env;
24
+ const env = context.env?.NODE_ENV || NODE_ENV;
25
+ const isProduction = env?.toLowerCase() === ignis_helpers_1.Environment.PRODUCTION;
26
+ const statusCode = 'statusCode' in error ? error.statusCode : ignis_helpers_1.HTTP.ResultCodes.RS_5.InternalServerError;
27
+ const messageCode = 'messageCode' in error ? error.messageCode : undefined;
28
+ if (error.name === 'ZodError') {
29
+ const rs = (0, zod_handler_1.formatZodError)({
30
+ isProduction,
31
+ requestId,
32
+ url: context.req.url,
33
+ path: context.req.path,
34
+ error,
35
+ });
36
+ return context.json(rootKey ? { [rootKey]: rs.response } : rs.response, rs.statusCode);
37
+ }
38
+ // Classify DB errors: client (400), transient/retryable conflict (409 Conflict), else server.
39
+ const dbError = (0, database_handler_1.isDatabaseClientError)({ error, isProduction });
40
+ const isRetryable = !dbError.isClientError && (0, database_handler_1.isRetryableDatabaseError)({ error });
41
+ let resolvedStatusCode = statusCode;
42
+ if (dbError.isClientError) {
43
+ resolvedStatusCode = ignis_helpers_1.HTTP.ResultCodes.RS_4.BadRequest;
44
+ }
45
+ else if (isRetryable) {
46
+ resolvedStatusCode = ignis_helpers_1.HTTP.ResultCodes.RS_4.Conflict;
47
+ }
48
+ let resolvedMessage = error.message;
49
+ let resolvedMessageCode = messageCode;
50
+ if (dbError.isClientError && dbError.message) {
51
+ resolvedMessage = dbError.message;
52
+ }
53
+ else if (isRetryable) {
54
+ // Transient conflict (deadlock / serialization failure) — safe generic message + retryable code.
55
+ resolvedMessage = definition_1.DATABASE_RETRYABLE_ERROR_MESSAGE;
56
+ resolvedMessageCode = definition_1.DATABASE_RETRYABLE_ERROR_CODE;
57
+ }
58
+ else if (isProduction && !('statusCode' in error)) {
59
+ // Unexpected server error (uncaught throw, non-client DB error, connection failure): never
60
+ // leak the raw message in production — it may carry SQL, schema names, or connection details.
61
+ resolvedMessage = DEFAULT_INTERNAL_ERROR_MESSAGE;
62
+ }
63
+ const rs = {
64
+ message: resolvedMessage,
65
+ messageCode: resolvedMessageCode,
66
+ statusCode: resolvedStatusCode,
67
+ requestId,
68
+ extra: 'extra' in error ? error?.extra : undefined,
69
+ details: {
70
+ url: context.req.url,
71
+ path: context.req.path,
72
+ stack: !isProduction ? error.stack : undefined,
73
+ cause: !isProduction ? error.cause : undefined,
74
+ },
75
+ };
76
+ return context.json(rootKey ? { [rootKey]: rs } : rs, resolvedStatusCode);
77
+ };
78
+ return mw;
79
+ };
80
+ exports.appErrorHandler = appErrorHandler;
81
+ //# sourceMappingURL=app-error.middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-error.middleware.js","sourceRoot":"","sources":["../../../../src/base/middlewares/app-error/app-error.middleware.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Checks if error is a database constraint error caused by the request (SQLSTATE class 22/23/44)
3
+ * and should return HTTP 400. In production the detail/table/constraint context is suppressed so
4
+ * no row values or schema internals leak; in non-production it is appended to aid debugging.
5
+ */
6
+ export declare const isDatabaseClientError: (opts: {
7
+ error: Error;
8
+ isProduction: boolean;
9
+ }) => {
10
+ isClientError: boolean;
11
+ message?: string;
12
+ };
13
+ /**
14
+ * Checks if error is a transient, retryable DB transaction conflict (serialization failure /
15
+ * deadlock — SQLSTATE 40001 / 40P01). These map to HTTP 409: the client can retry the same request.
16
+ */
17
+ export declare const isRetryableDatabaseError: (opts: {
18
+ error: Error;
19
+ }) => boolean;
20
+ //# sourceMappingURL=database.handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database.handler.d.ts","sourceRoot":"","sources":["../../../../src/base/middlewares/app-error/database.handler.ts"],"names":[],"mappings":"AAQA;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,GAAI,MAAM;IAC1C,KAAK,EAAE,KAAK,CAAC;IACb,YAAY,EAAE,OAAO,CAAC;CACvB,KAAG;IAAE,aAAa,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAyC7C,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,wBAAwB,GAAI,MAAM;IAAE,KAAK,EAAE,KAAK,CAAA;CAAE,KAAG,OAIjE,CAAC"}
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isRetryableDatabaseError = exports.isDatabaseClientError = void 0;
4
+ const definition_1 = require("./definition");
5
+ /**
6
+ * Checks if error is a database constraint error caused by the request (SQLSTATE class 22/23/44)
7
+ * and should return HTTP 400. In production the detail/table/constraint context is suppressed so
8
+ * no row values or schema internals leak; in non-production it is appended to aid debugging.
9
+ */
10
+ const isDatabaseClientError = (opts) => {
11
+ const { error, isProduction } = opts;
12
+ const dbError = error;
13
+ const cause = dbError.cause;
14
+ const code = dbError.code || cause?.code;
15
+ // Only SQLSTATE classes caused by the request — 22 (data exception) and 23 (integrity violation) —
16
+ // are client errors. Anything else (e.g. class 42 syntax/undefined-column, 53 resources) stays 500.
17
+ // A missing or non-string code (e.g. a gRPC numeric code) is treated as non-client and must never
18
+ // crash this last-resort handler.
19
+ if (typeof code !== 'string' || !definition_1.POSTGRES_CLIENT_ERROR_CLASSES.includes(code.slice(0, 2))) {
20
+ return { isClientError: false };
21
+ }
22
+ const baseMessage = definition_1.DATABASE_CLIENT_ERROR_MESSAGES[code] ?? definition_1.DATABASE_CLIENT_ERROR_FALLBACK_MESSAGE;
23
+ // In production, expose ONLY the generic base message. `detail` can echo row values
24
+ // (e.g. "Key (email)=(a@b.com) already exists") and `table`/`constraint` reveal schema internals.
25
+ if (isProduction) {
26
+ return { isClientError: true, message: baseMessage };
27
+ }
28
+ // Non-production: append driver-provided context to aid debugging.
29
+ const lines = [baseMessage];
30
+ if (cause?.detail) {
31
+ lines.push(`Detail: ${cause.detail}`);
32
+ }
33
+ if (cause?.table) {
34
+ lines.push(`Table: ${cause.table}`);
35
+ }
36
+ if (cause?.constraint) {
37
+ lines.push(`Constraint: ${cause.constraint}`);
38
+ }
39
+ return {
40
+ isClientError: true,
41
+ message: lines.join('\n'),
42
+ };
43
+ };
44
+ exports.isDatabaseClientError = isDatabaseClientError;
45
+ /**
46
+ * Checks if error is a transient, retryable DB transaction conflict (serialization failure /
47
+ * deadlock — SQLSTATE 40001 / 40P01). These map to HTTP 409: the client can retry the same request.
48
+ */
49
+ const isRetryableDatabaseError = (opts) => {
50
+ const dbError = opts.error;
51
+ const code = dbError.code || dbError.cause?.code;
52
+ return typeof code === 'string' && definition_1.POSTGRES_RETRYABLE_ERROR_CODES.includes(code);
53
+ };
54
+ exports.isRetryableDatabaseError = isRetryableDatabaseError;
55
+ //# sourceMappingURL=database.handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database.handler.js","sourceRoot":"","sources":["../../../../src/base/middlewares/app-error/database.handler.ts"],"names":[],"mappings":";;;AAAA,6CAKsB;AAGtB;;;;GAIG;AACI,MAAM,qBAAqB,GAAG,CAAC,IAGrC,EAAgD,EAAE;IACjD,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC;IACrC,MAAM,OAAO,GAAG,KAAuB,CAAC;IACxC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;IAC5B,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,KAAK,EAAE,IAAI,CAAC;IAEzC,mGAAmG;IACnG,oGAAoG;IACpG,kGAAkG;IAClG,kCAAkC;IAClC,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,0CAA6B,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1F,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC;IAClC,CAAC;IAED,MAAM,WAAW,GACf,2CAA8B,CAAC,IAAI,CAAC,IAAI,mDAAsC,CAAC;IAEjF,oFAAoF;IACpF,kGAAkG;IAClG,IAAI,YAAY,EAAE,CAAC;QACjB,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC;IACvD,CAAC;IAED,mEAAmE;IACnE,MAAM,KAAK,GAAG,CAAC,WAAW,CAAC,CAAC;IAC5B,IAAI,KAAK,EAAE,MAAM,EAAE,CAAC;QAClB,KAAK,CAAC,IAAI,CAAC,WAAW,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;IACxC,CAAC;IAED,IAAI,KAAK,EAAE,KAAK,EAAE,CAAC;QACjB,KAAK,CAAC,IAAI,CAAC,UAAU,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;IACtC,CAAC;IAED,IAAI,KAAK,EAAE,UAAU,EAAE,CAAC;QACtB,KAAK,CAAC,IAAI,CAAC,eAAe,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC;IAChD,CAAC;IAED,OAAO;QACL,aAAa,EAAE,IAAI;QACnB,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;KAC1B,CAAC;AACJ,CAAC,CAAC;AA5CW,QAAA,qBAAqB,yBA4ChC;AAEF;;;GAGG;AACI,MAAM,wBAAwB,GAAG,CAAC,IAAsB,EAAW,EAAE;IAC1E,MAAM,OAAO,GAAG,IAAI,CAAC,KAAuB,CAAC;IAC7C,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC;IACjD,OAAO,OAAO,IAAI,KAAK,QAAQ,IAAI,2CAA8B,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACnF,CAAC,CAAC;AAJW,QAAA,wBAAwB,4BAInC"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * PostgreSQL SQLSTATE error codes that represent a CLIENT error (HTTP 400) — i.e. caused by the
3
+ * request/data — rather than a server fault. Grouped by SQLSTATE class.
4
+ * @see https://www.postgresql.org/docs/current/errcodes-appendix.html
5
+ */
6
+ export declare const PostgresErrorCodes: {
7
+ readonly DATA_EXCEPTION: "22000";
8
+ readonly STRING_DATA_TOO_LONG: "22001";
9
+ readonly NUMERIC_VALUE_OUT_OF_RANGE: "22003";
10
+ readonly NULL_VALUE_NOT_ALLOWED: "22004";
11
+ readonly INVALID_DATETIME_FORMAT: "22007";
12
+ readonly DATETIME_FIELD_OVERFLOW: "22008";
13
+ readonly INVALID_TIME_ZONE_DISPLACEMENT_VALUE: "22009";
14
+ readonly SUBSTRING_ERROR: "22011";
15
+ readonly DIVISION_BY_ZERO: "22012";
16
+ readonly INVALID_PARAMETER_VALUE: "22023";
17
+ readonly INVALID_ESCAPE_SEQUENCE: "22025";
18
+ readonly STRING_DATA_LENGTH_MISMATCH: "22026";
19
+ readonly DUPLICATE_JSON_OBJECT_KEY_VALUE: "22030";
20
+ readonly INVALID_JSON_TEXT: "22032";
21
+ readonly FLOATING_POINT_EXCEPTION: "22P01";
22
+ readonly INVALID_TEXT_REPRESENTATION: "22P02";
23
+ readonly INVALID_BINARY_REPRESENTATION: "22P03";
24
+ readonly UNTRANSLATABLE_CHARACTER: "22P05";
25
+ readonly INTEGRITY_CONSTRAINT_VIOLATION: "23000";
26
+ readonly RESTRICT_VIOLATION: "23001";
27
+ readonly NOT_NULL_VIOLATION: "23502";
28
+ readonly FOREIGN_KEY_VIOLATION: "23503";
29
+ readonly UNIQUE_VIOLATION: "23505";
30
+ readonly CHECK_VIOLATION: "23514";
31
+ readonly EXCLUSION_VIOLATION: "23P01";
32
+ readonly WITH_CHECK_OPTION_VIOLATION: "44000";
33
+ };
34
+ /**
35
+ * SQLSTATE classes (first two chars) whose errors are caused by the client request and therefore
36
+ * map to HTTP 400. Any code in these classes — even one without a specific message below — is
37
+ * treated as a client error and uses {@link DATABASE_CLIENT_ERROR_FALLBACK_MESSAGE}.
38
+ *
39
+ * Deliberately excluded (remain server errors / 500): class 42 (syntax, undefined column/table —
40
+ * application/SQL bugs), 53 (insufficient resources), 0A (feature not supported), 25 (invalid
41
+ * transaction state), 28 (DB authorization), 21 (cardinality), 54 (program limits). Class 40
42
+ * (serialization_failure / deadlock_detected) is transient/retryable and is intentionally NOT a
43
+ * 400 — it warrants dedicated 409/503 + retry handling rather than being treated as client input.
44
+ */
45
+ export declare const POSTGRES_CLIENT_ERROR_CLASSES: readonly string[];
46
+ /** Human-readable message per specific SQLSTATE code. */
47
+ export declare const DATABASE_CLIENT_ERROR_MESSAGES: Record<string, string>;
48
+ /** Fallback message for a client-class (22/23/44) error that has no specific message above. */
49
+ export declare const DATABASE_CLIENT_ERROR_FALLBACK_MESSAGE = "Invalid database request";
50
+ /**
51
+ * SQLSTATE codes for transient, retryable transaction conflicts (→ HTTP 409 Conflict). The client
52
+ * can safely retry the same request: the transaction lost a concurrency race rather than sending
53
+ * bad input (not 400) or hitting a server bug (not 500). Retrying usually succeeds.
54
+ */
55
+ export declare const POSTGRES_RETRYABLE_ERROR_CODES: readonly string[];
56
+ /** Safe, generic message + stable code for a retryable DB conflict (never leaks internals). */
57
+ export declare const DATABASE_RETRYABLE_ERROR_MESSAGE = "The request conflicted with a concurrent operation; please retry.";
58
+ export declare const DATABASE_RETRYABLE_ERROR_CODE = "database.conflict";
59
+ //# sourceMappingURL=definition.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../../../src/base/middlewares/app-error/definition.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8BrB,CAAC;AAEX;;;;;;;;;;GAUG;AACH,eAAO,MAAM,6BAA6B,EAAE,SAAS,MAAM,EAAuB,CAAC;AAEnF,yDAAyD;AACzD,eAAO,MAAM,8BAA8B,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CA8BjE,CAAC;AAEF,+FAA+F;AAC/F,eAAO,MAAM,sCAAsC,6BAA6B,CAAC;AAEjF;;;;GAIG;AACH,eAAO,MAAM,8BAA8B,EAAE,SAAS,MAAM,EAG3D,CAAC;AAEF,+FAA+F;AAC/F,eAAO,MAAM,gCAAgC,sEACwB,CAAC;AACtE,eAAO,MAAM,6BAA6B,sBAAsB,CAAC"}
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DATABASE_RETRYABLE_ERROR_CODE = exports.DATABASE_RETRYABLE_ERROR_MESSAGE = exports.POSTGRES_RETRYABLE_ERROR_CODES = exports.DATABASE_CLIENT_ERROR_FALLBACK_MESSAGE = exports.DATABASE_CLIENT_ERROR_MESSAGES = exports.POSTGRES_CLIENT_ERROR_CLASSES = exports.PostgresErrorCodes = void 0;
4
+ /**
5
+ * PostgreSQL SQLSTATE error codes that represent a CLIENT error (HTTP 400) — i.e. caused by the
6
+ * request/data — rather than a server fault. Grouped by SQLSTATE class.
7
+ * @see https://www.postgresql.org/docs/current/errcodes-appendix.html
8
+ */
9
+ exports.PostgresErrorCodes = {
10
+ // Class 22 — Data Exception (malformed / out-of-range values)
11
+ DATA_EXCEPTION: '22000',
12
+ STRING_DATA_TOO_LONG: '22001',
13
+ NUMERIC_VALUE_OUT_OF_RANGE: '22003',
14
+ NULL_VALUE_NOT_ALLOWED: '22004',
15
+ INVALID_DATETIME_FORMAT: '22007',
16
+ DATETIME_FIELD_OVERFLOW: '22008',
17
+ INVALID_TIME_ZONE_DISPLACEMENT_VALUE: '22009',
18
+ SUBSTRING_ERROR: '22011',
19
+ DIVISION_BY_ZERO: '22012',
20
+ INVALID_PARAMETER_VALUE: '22023',
21
+ INVALID_ESCAPE_SEQUENCE: '22025',
22
+ STRING_DATA_LENGTH_MISMATCH: '22026',
23
+ DUPLICATE_JSON_OBJECT_KEY_VALUE: '22030',
24
+ INVALID_JSON_TEXT: '22032',
25
+ FLOATING_POINT_EXCEPTION: '22P01',
26
+ INVALID_TEXT_REPRESENTATION: '22P02',
27
+ INVALID_BINARY_REPRESENTATION: '22P03',
28
+ UNTRANSLATABLE_CHARACTER: '22P05',
29
+ // Class 23 — Integrity Constraint Violation
30
+ INTEGRITY_CONSTRAINT_VIOLATION: '23000',
31
+ RESTRICT_VIOLATION: '23001',
32
+ NOT_NULL_VIOLATION: '23502',
33
+ FOREIGN_KEY_VIOLATION: '23503',
34
+ UNIQUE_VIOLATION: '23505',
35
+ CHECK_VIOLATION: '23514',
36
+ EXCLUSION_VIOLATION: '23P01',
37
+ // Class 44 — WITH CHECK OPTION Violation (row written through an updatable view fails its CHECK)
38
+ WITH_CHECK_OPTION_VIOLATION: '44000',
39
+ };
40
+ /**
41
+ * SQLSTATE classes (first two chars) whose errors are caused by the client request and therefore
42
+ * map to HTTP 400. Any code in these classes — even one without a specific message below — is
43
+ * treated as a client error and uses {@link DATABASE_CLIENT_ERROR_FALLBACK_MESSAGE}.
44
+ *
45
+ * Deliberately excluded (remain server errors / 500): class 42 (syntax, undefined column/table —
46
+ * application/SQL bugs), 53 (insufficient resources), 0A (feature not supported), 25 (invalid
47
+ * transaction state), 28 (DB authorization), 21 (cardinality), 54 (program limits). Class 40
48
+ * (serialization_failure / deadlock_detected) is transient/retryable and is intentionally NOT a
49
+ * 400 — it warrants dedicated 409/503 + retry handling rather than being treated as client input.
50
+ */
51
+ exports.POSTGRES_CLIENT_ERROR_CLASSES = ['22', '23', '44'];
52
+ /** Human-readable message per specific SQLSTATE code. */
53
+ exports.DATABASE_CLIENT_ERROR_MESSAGES = {
54
+ // Class 22 — Data Exception
55
+ [exports.PostgresErrorCodes.DATA_EXCEPTION]: 'Invalid data value',
56
+ [exports.PostgresErrorCodes.STRING_DATA_TOO_LONG]: 'String data too long',
57
+ [exports.PostgresErrorCodes.NUMERIC_VALUE_OUT_OF_RANGE]: 'Numeric value out of range',
58
+ [exports.PostgresErrorCodes.NULL_VALUE_NOT_ALLOWED]: 'Null value not allowed',
59
+ [exports.PostgresErrorCodes.INVALID_DATETIME_FORMAT]: 'Invalid date/time format',
60
+ [exports.PostgresErrorCodes.DATETIME_FIELD_OVERFLOW]: 'Date/time field value out of range',
61
+ [exports.PostgresErrorCodes.INVALID_TIME_ZONE_DISPLACEMENT_VALUE]: 'Invalid time zone displacement value',
62
+ [exports.PostgresErrorCodes.SUBSTRING_ERROR]: 'Substring error',
63
+ [exports.PostgresErrorCodes.DIVISION_BY_ZERO]: 'Division by zero',
64
+ [exports.PostgresErrorCodes.INVALID_PARAMETER_VALUE]: 'Invalid parameter value',
65
+ [exports.PostgresErrorCodes.INVALID_ESCAPE_SEQUENCE]: 'Invalid escape sequence',
66
+ [exports.PostgresErrorCodes.STRING_DATA_LENGTH_MISMATCH]: 'String data length mismatch',
67
+ [exports.PostgresErrorCodes.DUPLICATE_JSON_OBJECT_KEY_VALUE]: 'Duplicate JSON object key',
68
+ [exports.PostgresErrorCodes.INVALID_JSON_TEXT]: 'Invalid JSON text',
69
+ [exports.PostgresErrorCodes.FLOATING_POINT_EXCEPTION]: 'Floating point exception',
70
+ [exports.PostgresErrorCodes.INVALID_TEXT_REPRESENTATION]: 'Invalid text representation',
71
+ [exports.PostgresErrorCodes.INVALID_BINARY_REPRESENTATION]: 'Invalid binary representation',
72
+ [exports.PostgresErrorCodes.UNTRANSLATABLE_CHARACTER]: 'Untranslatable character',
73
+ // Class 23 — Integrity Constraint Violation
74
+ [exports.PostgresErrorCodes.INTEGRITY_CONSTRAINT_VIOLATION]: 'Integrity constraint violation',
75
+ [exports.PostgresErrorCodes.RESTRICT_VIOLATION]: 'Restrict constraint violation',
76
+ [exports.PostgresErrorCodes.NOT_NULL_VIOLATION]: 'Not null constraint violation',
77
+ [exports.PostgresErrorCodes.FOREIGN_KEY_VIOLATION]: 'Foreign key constraint violation',
78
+ [exports.PostgresErrorCodes.UNIQUE_VIOLATION]: 'Unique constraint violation',
79
+ [exports.PostgresErrorCodes.CHECK_VIOLATION]: 'Check constraint violation',
80
+ [exports.PostgresErrorCodes.EXCLUSION_VIOLATION]: 'Exclusion constraint violation',
81
+ // Class 44 — WITH CHECK OPTION Violation
82
+ [exports.PostgresErrorCodes.WITH_CHECK_OPTION_VIOLATION]: 'View check option violation',
83
+ };
84
+ /** Fallback message for a client-class (22/23/44) error that has no specific message above. */
85
+ exports.DATABASE_CLIENT_ERROR_FALLBACK_MESSAGE = 'Invalid database request';
86
+ /**
87
+ * SQLSTATE codes for transient, retryable transaction conflicts (→ HTTP 409 Conflict). The client
88
+ * can safely retry the same request: the transaction lost a concurrency race rather than sending
89
+ * bad input (not 400) or hitting a server bug (not 500). Retrying usually succeeds.
90
+ */
91
+ exports.POSTGRES_RETRYABLE_ERROR_CODES = [
92
+ '40001', // serialization_failure
93
+ '40P01', // deadlock_detected
94
+ ];
95
+ /** Safe, generic message + stable code for a retryable DB conflict (never leaks internals). */
96
+ exports.DATABASE_RETRYABLE_ERROR_MESSAGE = 'The request conflicted with a concurrent operation; please retry.';
97
+ exports.DATABASE_RETRYABLE_ERROR_CODE = 'database.conflict';
98
+ //# sourceMappingURL=definition.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"definition.js","sourceRoot":"","sources":["../../../../src/base/middlewares/app-error/definition.ts"],"names":[],"mappings":";;;AAAA;;;;GAIG;AACU,QAAA,kBAAkB,GAAG;IAChC,8DAA8D;IAC9D,cAAc,EAAE,OAAO;IACvB,oBAAoB,EAAE,OAAO;IAC7B,0BAA0B,EAAE,OAAO;IACnC,sBAAsB,EAAE,OAAO;IAC/B,uBAAuB,EAAE,OAAO;IAChC,uBAAuB,EAAE,OAAO;IAChC,oCAAoC,EAAE,OAAO;IAC7C,eAAe,EAAE,OAAO;IACxB,gBAAgB,EAAE,OAAO;IACzB,uBAAuB,EAAE,OAAO;IAChC,uBAAuB,EAAE,OAAO;IAChC,2BAA2B,EAAE,OAAO;IACpC,+BAA+B,EAAE,OAAO;IACxC,iBAAiB,EAAE,OAAO;IAC1B,wBAAwB,EAAE,OAAO;IACjC,2BAA2B,EAAE,OAAO;IACpC,6BAA6B,EAAE,OAAO;IACtC,wBAAwB,EAAE,OAAO;IACjC,4CAA4C;IAC5C,8BAA8B,EAAE,OAAO;IACvC,kBAAkB,EAAE,OAAO;IAC3B,kBAAkB,EAAE,OAAO;IAC3B,qBAAqB,EAAE,OAAO;IAC9B,gBAAgB,EAAE,OAAO;IACzB,eAAe,EAAE,OAAO;IACxB,mBAAmB,EAAE,OAAO;IAC5B,iGAAiG;IACjG,2BAA2B,EAAE,OAAO;CAC5B,CAAC;AAEX;;;;;;;;;;GAUG;AACU,QAAA,6BAA6B,GAAsB,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AAEnF,yDAAyD;AAC5C,QAAA,8BAA8B,GAA2B;IACpE,4BAA4B;IAC5B,CAAC,0BAAkB,CAAC,cAAc,CAAC,EAAE,oBAAoB;IACzD,CAAC,0BAAkB,CAAC,oBAAoB,CAAC,EAAE,sBAAsB;IACjE,CAAC,0BAAkB,CAAC,0BAA0B,CAAC,EAAE,4BAA4B;IAC7E,CAAC,0BAAkB,CAAC,sBAAsB,CAAC,EAAE,wBAAwB;IACrE,CAAC,0BAAkB,CAAC,uBAAuB,CAAC,EAAE,0BAA0B;IACxE,CAAC,0BAAkB,CAAC,uBAAuB,CAAC,EAAE,oCAAoC;IAClF,CAAC,0BAAkB,CAAC,oCAAoC,CAAC,EAAE,sCAAsC;IACjG,CAAC,0BAAkB,CAAC,eAAe,CAAC,EAAE,iBAAiB;IACvD,CAAC,0BAAkB,CAAC,gBAAgB,CAAC,EAAE,kBAAkB;IACzD,CAAC,0BAAkB,CAAC,uBAAuB,CAAC,EAAE,yBAAyB;IACvE,CAAC,0BAAkB,CAAC,uBAAuB,CAAC,EAAE,yBAAyB;IACvE,CAAC,0BAAkB,CAAC,2BAA2B,CAAC,EAAE,6BAA6B;IAC/E,CAAC,0BAAkB,CAAC,+BAA+B,CAAC,EAAE,2BAA2B;IACjF,CAAC,0BAAkB,CAAC,iBAAiB,CAAC,EAAE,mBAAmB;IAC3D,CAAC,0BAAkB,CAAC,wBAAwB,CAAC,EAAE,0BAA0B;IACzE,CAAC,0BAAkB,CAAC,2BAA2B,CAAC,EAAE,6BAA6B;IAC/E,CAAC,0BAAkB,CAAC,6BAA6B,CAAC,EAAE,+BAA+B;IACnF,CAAC,0BAAkB,CAAC,wBAAwB,CAAC,EAAE,0BAA0B;IACzE,4CAA4C;IAC5C,CAAC,0BAAkB,CAAC,8BAA8B,CAAC,EAAE,gCAAgC;IACrF,CAAC,0BAAkB,CAAC,kBAAkB,CAAC,EAAE,+BAA+B;IACxE,CAAC,0BAAkB,CAAC,kBAAkB,CAAC,EAAE,+BAA+B;IACxE,CAAC,0BAAkB,CAAC,qBAAqB,CAAC,EAAE,kCAAkC;IAC9E,CAAC,0BAAkB,CAAC,gBAAgB,CAAC,EAAE,6BAA6B;IACpE,CAAC,0BAAkB,CAAC,eAAe,CAAC,EAAE,4BAA4B;IAClE,CAAC,0BAAkB,CAAC,mBAAmB,CAAC,EAAE,gCAAgC;IAC1E,yCAAyC;IACzC,CAAC,0BAAkB,CAAC,2BAA2B,CAAC,EAAE,6BAA6B;CAChF,CAAC;AAEF,+FAA+F;AAClF,QAAA,sCAAsC,GAAG,0BAA0B,CAAC;AAEjF;;;;GAIG;AACU,QAAA,8BAA8B,GAAsB;IAC/D,OAAO,EAAE,wBAAwB;IACjC,OAAO,EAAE,oBAAoB;CAC9B,CAAC;AAEF,+FAA+F;AAClF,QAAA,gCAAgC,GAC3C,mEAAmE,CAAC;AACzD,QAAA,6BAA6B,GAAG,mBAAmB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export * from './app-error.middleware';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/base/middlewares/app-error/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC"}
@@ -14,6 +14,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./string-action.model"), exports);
18
- __exportStar(require("./string-resource.model"), exports);
17
+ __exportStar(require("./app-error.middleware"), exports);
19
18
  //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/base/middlewares/app-error/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,yDAAuC"}
@@ -0,0 +1,18 @@
1
+ export interface IDatabaseError extends Error {
2
+ code?: string;
3
+ cause?: {
4
+ code?: string;
5
+ detail?: string;
6
+ table?: string;
7
+ constraint?: string;
8
+ };
9
+ }
10
+ export interface IZodIssueLike {
11
+ path: Array<string | number>;
12
+ message: string;
13
+ code?: string;
14
+ params?: Record<string, unknown>;
15
+ expected?: unknown;
16
+ received?: unknown;
17
+ }
18
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/base/middlewares/app-error/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAe,SAAQ,KAAK;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE;QACN,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;CACH;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/base/middlewares/app-error/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,28 @@
1
+ import { HTTPResponseError } from 'hono/types';
2
+ /**
3
+ * Formats a ZodError into the 422 validation response. Top-level `messageCode`/`message` come from
4
+ * the first issue that defines a custom `params.code`, else the first issue's raw Zod code; the full
5
+ * per-issue list stays under `details.cause`.
6
+ */
7
+ export declare const formatZodError: (opts: {
8
+ isProduction: boolean;
9
+ requestId: string;
10
+ url: string;
11
+ path: string;
12
+ error: Error | HTTPResponseError;
13
+ }) => {
14
+ statusCode: 422;
15
+ response: {
16
+ message: string;
17
+ messageCode: string | undefined;
18
+ statusCode: 422;
19
+ requestId: string;
20
+ details: {
21
+ url: string;
22
+ path: string;
23
+ stack: string | undefined;
24
+ cause: unknown;
25
+ };
26
+ };
27
+ };
28
+ //# sourceMappingURL=zod.handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zod.handler.d.ts","sourceRoot":"","sources":["../../../../src/base/middlewares/app-error/zod.handler.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAgB/C;;;;GAIG;AACH,eAAO,MAAM,cAAc,GAAI,MAAM;IACnC,YAAY,EAAE,OAAO,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,KAAK,GAAG,iBAAiB,CAAC;CAClC;;;;;;;;;;;;;;CAgDA,CAAC"}
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.formatZodError = void 0;
4
+ const ignis_helpers_1 = require("@venizia/ignis-helpers");
5
+ const DEFAULT_VALIDATION_MESSAGE = 'ValidationError';
6
+ /** Returns a schema-author-supplied code (`issue.params.code`) when it is a non-empty string. */
7
+ const extractIssueCode = (opts) => {
8
+ const paramsCode = opts.issue?.params?.code;
9
+ if (typeof paramsCode === 'string' && paramsCode.length > 0) {
10
+ return paramsCode;
11
+ }
12
+ return undefined;
13
+ };
14
+ /**
15
+ * Formats a ZodError into the 422 validation response. Top-level `messageCode`/`message` come from
16
+ * the first issue that defines a custom `params.code`, else the first issue's raw Zod code; the full
17
+ * per-issue list stays under `details.cause`.
18
+ */
19
+ const formatZodError = (opts) => {
20
+ const { isProduction, requestId, url, path, error } = opts;
21
+ const statusCode = ignis_helpers_1.HTTP.ResultCodes.RS_4.UnprocessableEntity;
22
+ let validationErrors;
23
+ try {
24
+ validationErrors = JSON.parse(error.message);
25
+ }
26
+ catch {
27
+ validationErrors = error;
28
+ }
29
+ const issues = Array.isArray(validationErrors) ? validationErrors : null;
30
+ // Top-level messageCode/message: prefer the first issue with a custom `params.code`;
31
+ // else fall back to the first issue's raw Zod code; else keep the generic message.
32
+ let messageCode;
33
+ let message = DEFAULT_VALIDATION_MESSAGE;
34
+ if (issues && issues.length > 0) {
35
+ const primaryIssue = issues.find(issue => extractIssueCode({ issue }) !== undefined) ?? issues[0];
36
+ messageCode = extractIssueCode({ issue: primaryIssue }) ?? primaryIssue.code;
37
+ message = primaryIssue.message;
38
+ }
39
+ return {
40
+ statusCode,
41
+ response: {
42
+ message,
43
+ messageCode,
44
+ statusCode,
45
+ requestId,
46
+ details: {
47
+ url,
48
+ path,
49
+ stack: !isProduction ? error.stack : undefined,
50
+ cause: issues
51
+ ? issues.map(el => ({
52
+ path: el.path.join('.') || 'root',
53
+ message: el.message,
54
+ code: el.code,
55
+ expected: el.expected,
56
+ received: el.received,
57
+ }))
58
+ : validationErrors,
59
+ },
60
+ },
61
+ };
62
+ };
63
+ exports.formatZodError = formatZodError;
64
+ //# sourceMappingURL=zod.handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zod.handler.js","sourceRoot":"","sources":["../../../../src/base/middlewares/app-error/zod.handler.ts"],"names":[],"mappings":";;;AAAA,0DAA8C;AAI9C,MAAM,0BAA0B,GAAG,iBAAiB,CAAC;AAErD,iGAAiG;AACjG,MAAM,gBAAgB,GAAG,CAAC,IAA8B,EAAE,EAAE;IAC1D,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC;IAE5C,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5D,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC;AAEF;;;;GAIG;AACI,MAAM,cAAc,GAAG,CAAC,IAM9B,EAAE,EAAE;IACH,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC;IAC3D,MAAM,UAAU,GAAG,oBAAI,CAAC,WAAW,CAAC,IAAI,CAAC,mBAAmB,CAAC;IAE7D,IAAI,gBAAyB,CAAC;IAC9B,IAAI,CAAC;QACH,gBAAgB,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,gBAAgB,GAAG,KAAK,CAAC;IAC3B,CAAC;IAED,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAE,gBAAoC,CAAC,CAAC,CAAC,IAAI,CAAC;IAE9F,qFAAqF;IACrF,mFAAmF;IACnF,IAAI,WAA+B,CAAC;IACpC,IAAI,OAAO,GAAG,0BAA0B,CAAC;IAEzC,IAAI,MAAM,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChC,MAAM,YAAY,GAChB,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,SAAS,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC;QAC/E,WAAW,GAAG,gBAAgB,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC,IAAI,YAAY,CAAC,IAAI,CAAC;QAC7E,OAAO,GAAG,YAAY,CAAC,OAAO,CAAC;IACjC,CAAC;IAED,OAAO;QACL,UAAU;QACV,QAAQ,EAAE;YACR,OAAO;YACP,WAAW;YACX,UAAU;YACV,SAAS;YACT,OAAO,EAAE;gBACP,GAAG;gBACH,IAAI;gBACJ,KAAK,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS;gBAC9C,KAAK,EAAE,MAAM;oBACX,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;wBAChB,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,MAAM;wBACjC,OAAO,EAAE,EAAE,CAAC,OAAO;wBACnB,IAAI,EAAE,EAAE,CAAC,IAAI;wBACb,QAAQ,EAAE,EAAE,CAAC,QAAQ;wBACrB,QAAQ,EAAE,EAAE,CAAC,QAAQ;qBACtB,CAAC,CAAC;oBACL,CAAC,CAAC,gBAAgB;aACrB;SACF;KACF,CAAC;AACJ,CAAC,CAAC;AAtDW,QAAA,cAAc,kBAsDzB"}