@venizia/ignis-kernel 0.4.7-0 → 0.4.7-1

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 (161) hide show
  1. package/LICENSE.md +1 -4
  2. package/dist/esm/base/applications/cors.d.ts +12 -10
  3. package/dist/esm/base/applications/cors.d.ts.map +1 -1
  4. package/dist/esm/base/applications/cors.js +37 -35
  5. package/dist/esm/base/applications/cors.js.map +1 -1
  6. package/dist/esm/base/applications/rest.js +11 -11
  7. package/dist/esm/base/applications/rest.js.map +1 -1
  8. package/dist/esm/base/auth/authenticate/common/codecs.js +2 -2
  9. package/dist/esm/base/auth/authenticate/common/codecs.js.map +1 -1
  10. package/dist/esm/base/auth/authenticate/strategies/strategy-registry.d.ts +1 -1
  11. package/dist/esm/base/auth/authenticate/strategies/strategy-registry.js +1 -1
  12. package/dist/esm/base/auth/authenticate/strategies/strategy-registry.js.map +1 -1
  13. package/dist/esm/base/auth/authorize/providers/authorization.provider.js +7 -7
  14. package/dist/esm/base/auth/authorize/providers/authorization.provider.js.map +1 -1
  15. package/dist/esm/base/auth/authorize/providers/request-domain.d.ts +14 -11
  16. package/dist/esm/base/auth/authorize/providers/request-domain.d.ts.map +1 -1
  17. package/dist/esm/base/auth/authorize/providers/request-domain.js +42 -39
  18. package/dist/esm/base/auth/authorize/providers/request-domain.js.map +1 -1
  19. package/dist/esm/base/auth/base/abstract-auth-registry.js +2 -2
  20. package/dist/esm/base/auth/base/abstract-auth-registry.js.map +1 -1
  21. package/dist/esm/base/auth/models/requests/change-password.schema.js +3 -3
  22. package/dist/esm/base/auth/models/requests/change-password.schema.js.map +1 -1
  23. package/dist/esm/base/auth/models/requests/sign-in.schema.js +5 -5
  24. package/dist/esm/base/auth/models/requests/sign-in.schema.js.map +1 -1
  25. package/dist/esm/base/components/controller/rest/rest.component.js +2 -2
  26. package/dist/esm/base/components/controller/rest/rest.component.js.map +1 -1
  27. package/dist/esm/base/controllers/common/index.d.ts +0 -1
  28. package/dist/esm/base/controllers/common/index.d.ts.map +1 -1
  29. package/dist/esm/base/controllers/common/index.js +0 -1
  30. package/dist/esm/base/controllers/common/index.js.map +1 -1
  31. package/dist/esm/base/controllers/common/schema-builders.d.ts +0 -5
  32. package/dist/esm/base/controllers/common/schema-builders.d.ts.map +1 -1
  33. package/dist/esm/base/controllers/common/schema-builders.js +0 -14
  34. package/dist/esm/base/controllers/common/schema-builders.js.map +1 -1
  35. package/dist/esm/base/controllers/context.d.ts +7 -2
  36. package/dist/esm/base/controllers/context.d.ts.map +1 -1
  37. package/dist/esm/base/controllers/context.js +7 -4
  38. package/dist/esm/base/controllers/context.js.map +1 -1
  39. package/dist/esm/base/controllers/factory/controller.d.ts +33 -1
  40. package/dist/esm/base/controllers/factory/controller.d.ts.map +1 -1
  41. package/dist/esm/base/controllers/factory/controller.js +90 -6
  42. package/dist/esm/base/controllers/factory/controller.js.map +1 -1
  43. package/dist/esm/base/controllers/factory/definition.d.ts +1 -8
  44. package/dist/esm/base/controllers/factory/definition.d.ts.map +1 -1
  45. package/dist/esm/base/controllers/factory/definition.js +17 -24
  46. package/dist/esm/base/controllers/factory/definition.js.map +1 -1
  47. package/dist/esm/base/controllers/factory/index.d.ts +0 -1
  48. package/dist/esm/base/controllers/factory/index.d.ts.map +1 -1
  49. package/dist/esm/base/controllers/factory/index.js +0 -1
  50. package/dist/esm/base/controllers/factory/index.js.map +1 -1
  51. package/dist/esm/base/controllers/rest/abstract.d.ts.map +1 -1
  52. package/dist/esm/base/controllers/rest/abstract.js +6 -6
  53. package/dist/esm/base/controllers/rest/abstract.js.map +1 -1
  54. package/dist/esm/base/controllers/rest/base.d.ts +0 -5
  55. package/dist/esm/base/controllers/rest/base.d.ts.map +1 -1
  56. package/dist/esm/base/controllers/rest/base.js +14 -14
  57. package/dist/esm/base/controllers/rest/base.js.map +1 -1
  58. package/dist/esm/base/datasources/abstract.js +2 -2
  59. package/dist/esm/base/datasources/abstract.js.map +1 -1
  60. package/dist/esm/base/events/event-bus.js +4 -4
  61. package/dist/esm/base/events/event-bus.js.map +1 -1
  62. package/dist/esm/base/metadata/injectable.d.ts +7 -4
  63. package/dist/esm/base/metadata/injectable.d.ts.map +1 -1
  64. package/dist/esm/base/metadata/injectable.js +26 -23
  65. package/dist/esm/base/metadata/injectable.js.map +1 -1
  66. package/dist/esm/base/metadata/model-metadata.d.ts +27 -13
  67. package/dist/esm/base/metadata/model-metadata.d.ts.map +1 -1
  68. package/dist/esm/base/metadata/model-metadata.js +56 -26
  69. package/dist/esm/base/metadata/model-metadata.js.map +1 -1
  70. package/dist/esm/base/metadata/persistents.d.ts.map +1 -1
  71. package/dist/esm/base/metadata/persistents.js +21 -13
  72. package/dist/esm/base/metadata/persistents.js.map +1 -1
  73. package/dist/esm/base/metadata/routes/controller.d.ts.map +1 -1
  74. package/dist/esm/base/metadata/routes/controller.js +5 -2
  75. package/dist/esm/base/metadata/routes/controller.js.map +1 -1
  76. package/dist/esm/base/middlewares/app-error/app-error.middleware.js +7 -7
  77. package/dist/esm/base/middlewares/app-error/app-error.middleware.js.map +1 -1
  78. package/dist/esm/base/middlewares/app-error/database.handler.d.ts +14 -12
  79. package/dist/esm/base/middlewares/app-error/database.handler.d.ts.map +1 -1
  80. package/dist/esm/base/middlewares/app-error/database.handler.js +37 -35
  81. package/dist/esm/base/middlewares/app-error/database.handler.js.map +1 -1
  82. package/dist/esm/base/middlewares/app-error/zod.handler.d.ts +28 -23
  83. package/dist/esm/base/middlewares/app-error/zod.handler.d.ts.map +1 -1
  84. package/dist/esm/base/middlewares/app-error/zod.handler.js +56 -53
  85. package/dist/esm/base/middlewares/app-error/zod.handler.js.map +1 -1
  86. package/dist/esm/base/middlewares/emoji-favicon/emoji-favicon.middleware.d.ts +6 -4
  87. package/dist/esm/base/middlewares/emoji-favicon/emoji-favicon.middleware.d.ts.map +1 -1
  88. package/dist/esm/base/middlewares/emoji-favicon/emoji-favicon.middleware.js +14 -12
  89. package/dist/esm/base/middlewares/emoji-favicon/emoji-favicon.middleware.js.map +1 -1
  90. package/dist/esm/base/middlewares/form-body/form-body.middleware.d.ts +15 -11
  91. package/dist/esm/base/middlewares/form-body/form-body.middleware.d.ts.map +1 -1
  92. package/dist/esm/base/middlewares/form-body/form-body.middleware.js +25 -21
  93. package/dist/esm/base/middlewares/form-body/form-body.middleware.js.map +1 -1
  94. package/dist/esm/base/models/common/schemas.d.ts +184 -105
  95. package/dist/esm/base/models/common/schemas.d.ts.map +1 -1
  96. package/dist/esm/base/models/common/schemas.js +105 -54
  97. package/dist/esm/base/models/common/schemas.js.map +1 -1
  98. package/dist/esm/base/models/common/utilities.d.ts +10 -5
  99. package/dist/esm/base/models/common/utilities.d.ts.map +1 -1
  100. package/dist/esm/base/models/common/utilities.js +22 -16
  101. package/dist/esm/base/models/common/utilities.js.map +1 -1
  102. package/dist/esm/base/repositories/common/types/results.d.ts +15 -7
  103. package/dist/esm/base/repositories/common/types/results.d.ts.map +1 -1
  104. package/dist/esm/base/repositories/common/types/results.js +16 -7
  105. package/dist/esm/base/repositories/common/types/results.js.map +1 -1
  106. package/dist/esm/base/repositories/core/abstract.d.ts.map +1 -1
  107. package/dist/esm/base/repositories/core/abstract.js +5 -3
  108. package/dist/esm/base/repositories/core/abstract.js.map +1 -1
  109. package/dist/esm/base/repositories/query-schemas/index.d.ts +1 -1
  110. package/dist/esm/base/repositories/query-schemas/index.d.ts.map +1 -1
  111. package/dist/esm/base/repositories/query-schemas/index.js +3 -3
  112. package/dist/esm/base/repositories/query-schemas/index.js.map +1 -1
  113. package/dist/esm/helpers/inversion/common/relation-builder.js.map +1 -1
  114. package/dist/esm/helpers/inversion/index.d.ts +1 -1
  115. package/dist/esm/helpers/inversion/index.d.ts.map +1 -1
  116. package/dist/esm/helpers/inversion/index.js +1 -1
  117. package/dist/esm/helpers/inversion/index.js.map +1 -1
  118. package/dist/esm/helpers/inversion/mixins/repository.mixin.d.ts.map +1 -1
  119. package/dist/esm/helpers/inversion/mixins/repository.mixin.js +5 -5
  120. package/dist/esm/helpers/inversion/mixins/repository.mixin.js.map +1 -1
  121. package/dist/esm/metadata.d.ts +1 -1
  122. package/dist/esm/metadata.d.ts.map +1 -1
  123. package/dist/esm/metadata.js +1 -1
  124. package/dist/esm/metadata.js.map +1 -1
  125. package/dist/esm/repository.d.ts +2 -2
  126. package/dist/esm/repository.d.ts.map +1 -1
  127. package/dist/esm/repository.js +2 -2
  128. package/dist/esm/repository.js.map +1 -1
  129. package/dist/esm/utilities/index.d.ts +1 -1
  130. package/dist/esm/utilities/index.d.ts.map +1 -1
  131. package/dist/esm/utilities/index.js +1 -1
  132. package/dist/esm/utilities/index.js.map +1 -1
  133. package/dist/esm/utilities/not-supported.utility.d.ts +11 -0
  134. package/dist/esm/utilities/not-supported.utility.d.ts.map +1 -0
  135. package/dist/esm/utilities/not-supported.utility.js +19 -0
  136. package/dist/esm/utilities/not-supported.utility.js.map +1 -0
  137. package/package.json +6 -7
  138. package/dist/esm/base/controllers/common/html-response.d.ts +0 -70
  139. package/dist/esm/base/controllers/common/html-response.d.ts.map +0 -1
  140. package/dist/esm/base/controllers/common/html-response.js +0 -30
  141. package/dist/esm/base/controllers/common/html-response.js.map +0 -1
  142. package/dist/esm/base/controllers/factory/authorize-guard.d.ts +0 -19
  143. package/dist/esm/base/controllers/factory/authorize-guard.d.ts.map +0 -1
  144. package/dist/esm/base/controllers/factory/authorize-guard.js +0 -56
  145. package/dist/esm/base/controllers/factory/authorize-guard.js.map +0 -1
  146. package/dist/esm/base/controllers/factory/helper.d.ts +0 -2
  147. package/dist/esm/base/controllers/factory/helper.d.ts.map +0 -1
  148. package/dist/esm/base/controllers/factory/helper.js +0 -2
  149. package/dist/esm/base/controllers/factory/helper.js.map +0 -1
  150. package/dist/esm/base/controllers/factory/repository-injection.d.ts +0 -14
  151. package/dist/esm/base/controllers/factory/repository-injection.d.ts.map +0 -1
  152. package/dist/esm/base/controllers/factory/repository-injection.js +0 -27
  153. package/dist/esm/base/controllers/factory/repository-injection.js.map +0 -1
  154. package/dist/esm/base/metadata/model-settings.d.ts +0 -11
  155. package/dist/esm/base/metadata/model-settings.d.ts.map +0 -1
  156. package/dist/esm/base/metadata/model-settings.js +0 -30
  157. package/dist/esm/base/metadata/model-settings.js.map +0 -1
  158. package/dist/esm/utilities/error.utility.d.ts +0 -8
  159. package/dist/esm/utilities/error.utility.d.ts.map +0 -1
  160. package/dist/esm/utilities/error.utility.js +0 -14
  161. package/dist/esm/utilities/error.utility.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"persistents.js","sourceRoot":"","sources":["../../../../src/base/metadata/persistents.ts"],"names":[],"mappings":"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","sourcesContent":["import { BindingNamespaces } from '@/common/bindings';\nimport type {\n IArtifactRegistrationOptions,\n IDataSourceMetadata,\n IInjectMetadata,\n IModelMetadata,\n IResolvedRepositoryMetadata,\n TRepositoryMetadata,\n} from '@/helpers/inversion';\nimport {\n ArtifactTypes,\n BindingKeys,\n MetadataKeys,\n MetadataRegistry,\n resolveInjectTarget,\n} from '@/helpers/inversion';\nimport { resolveClass, resolveValue } from '@venizia/ignis-helpers/common';\nimport { getError } from '@venizia/ignis-helpers/core';\nimport type { IDataSource } from '../datasources';\nimport { isDataSourceClass } from '../datasources';\nimport type { AbstractEntity } from '../models';\nimport { RepositoryTypes } from '../repositories/common/constants';\nimport { injectable, pickRegistrationOptions } from './injectable';\nimport { normalizeModelMetadata } from './model-metadata';\nimport { assertNoRemovedModelSettings } from './model-settings';\n\n/** Registers a model class with its static schema and relations. */\nexport const model = (input: IModelMetadata = {}): ClassDecorator => {\n return (target) => {\n injectable({ type: ArtifactTypes.MODEL, ...pickRegistrationOptions({ metadata: input }) })(\n target,\n );\n\n const metadata = normalizeModelMetadata({ model: target.name, metadata: input });\n\n assertNoRemovedModelSettings({ model: target.name, settings: metadata.settings });\n const { settings } = metadata;\n\n const defaultLimit = settings?.query?.limit?.default;\n if (defaultLimit !== undefined && (!Number.isInteger(defaultLimit) || defaultLimit <= 0)) {\n throw getError({\n message: `[model][${target.name}] Invalid 'query.limit.default' | Expected a positive integer | Got: ${defaultLimit}`,\n });\n }\n\n // Validated at DECORATION time, like the default limit: a bad ceiling is a wiring mistake, and\n // catching it at boot beats catching it on the one request that happens to reach the limit.\n const maxLimit = settings?.query?.limit?.max;\n if (maxLimit !== undefined && (!Number.isInteger(maxLimit) || maxLimit <= 0)) {\n throw getError({\n message: `[model][${target.name}] Invalid 'query.limit.max' | Expected a positive integer | Got: ${maxLimit}`,\n });\n }\n\n // Auto-populate AUTHORIZATION_SUBJECT from authorize.principal if not already set\n const principal = settings?.authorize?.principal;\n if (principal && !Object.hasOwn(target, 'AUTHORIZATION_SUBJECT')) {\n (target as Record<string, unknown>).AUTHORIZATION_SUBJECT = principal;\n }\n\n MetadataRegistry.getInstance().registerModel({ target, metadata });\n };\n};\n\n/** Registers a datasource with driver and auto-discovery settings. */\nexport const datasource = (metadata?: IDataSourceMetadata): ClassDecorator => {\n return (target) => {\n injectable({\n type: ArtifactTypes.DATASOURCE,\n ...pickRegistrationOptions({ metadata: metadata ?? {} }),\n })(target);\n MetadataRegistry.getInstance().setDataSourceMetadata({ target, metadata });\n };\n};\n\n/** Mirrors the `TRepositoryMetadata` union for JavaScript callers: a known type, a dataSource always, a model exactly when the type is RepositoryTypes.MODEL. */\nconst validateRepositoryMetadata = <\n Model extends AbstractEntity = AbstractEntity,\n DataSource extends IDataSource = IDataSource,\n>(opts: {\n metadata: TRepositoryMetadata<Model, DataSource>;\n target: Function;\n}): void => {\n const { metadata, target } = opts;\n const type = metadata.type ?? RepositoryTypes.MODEL;\n\n if (!RepositoryTypes.isValid(type)) {\n throw getError({\n message: `[validateRepositoryMetadata][@repository][${target.name}] Invalid metadata | Unknown 'type': ${type} | Expected one of: ${[...RepositoryTypes.SCHEME_SET].join(', ')}`,\n });\n }\n\n if (type === RepositoryTypes.MODEL && !metadata.model) {\n throw getError({\n message: `[validateRepositoryMetadata][@repository][${target.name}] Invalid metadata | Missing 'model'`,\n });\n }\n\n if (type === RepositoryTypes.REMOTE && metadata.model) {\n throw getError({\n message: `[validateRepositoryMetadata][@repository][${target.name}] Invalid metadata | A '${RepositoryTypes.REMOTE}' repository takes no 'model'`,\n });\n }\n\n if (!metadata.dataSource) {\n throw getError({\n message: `[validateRepositoryMetadata][@repository][${target.name}] Invalid metadata | Missing 'dataSource'`,\n });\n }\n};\n\n/** Asserts the constructor's first parameter is an AbstractDataSource compatible with what @repository declared. */\nconst validateFirstConstructorParameter = (opts: {\n target: Function;\n firstParamType: Function;\n resolvedDataSource: string | Function;\n}): void => {\n const { target, firstParamType, resolvedDataSource } = opts;\n\n // NOT `instanceof`: two copies of this package give two `AbstractDataSource` classes and the\n // check would be false across them, rejecting a perfectly valid repository at import time.\n const isDataSourceType = isDataSourceClass(firstParamType);\n\n if (!isDataSourceType) {\n throw getError({\n message: `[@repository][${target.name}] Invalid constructor | First parameter must extend AbstractDataSource | Received: '${firstParamType.name}'`,\n });\n }\n\n if (typeof resolvedDataSource !== 'function') {\n return;\n }\n\n const isCompatible =\n firstParamType === resolvedDataSource || resolvedDataSource.prototype instanceof firstParamType;\n\n if (!isCompatible) {\n throw getError({\n message: `[@repository][${target.name}] Invalid constructor | Type mismatch | Constructor expects '${firstParamType.name}' but @repository specifies '${resolvedDataSource.name}'`,\n });\n }\n};\n\n/**\n * Auto-injects dataSource at constructor param[0] unless explicit @inject exists. A class is injected\n * by the class itself, so the container reads the key its registration recorded: a pinned\n * `binding` and a minified class name both resolve. Only a string reference is a key.\n */\nconst registerDataSourceInjection = (opts: {\n target: Function;\n registry: MetadataRegistry;\n dataSourceRef: TRepositoryMetadata['dataSource'];\n resolvedDataSource: string | Function;\n}): void => {\n const { target, registry, dataSourceRef, resolvedDataSource } = opts;\n\n // Own metadata only: `getInjectMetadata` walks the prototype chain, so a repository extending another @repository class would see the BASE's injection at param[0] and silently resolve the base's dataSource.\n const ownInjects: IInjectMetadata[] | undefined = Reflect.getOwnMetadata(\n MetadataKeys.INJECT,\n target,\n );\n const injectAtIndex0 = ownInjects?.find((entry) => entry?.index === 0);\n\n if (injectAtIndex0) {\n // `@inject({ target })` carries no key; read the one recorded on the class. The function form\n // resolves through the same helper the container uses, so both paths read one class.\n const injectedTarget = injectAtIndex0.target\n ? resolveInjectTarget({ target: injectAtIndex0.target })\n : undefined;\n const injectKey =\n injectAtIndex0.key ??\n (injectedTarget ? registry.getBindingKey({ target: injectedTarget }) : undefined);\n\n // A class is judged by its brand: its key may sit under any namespace a `binding` pinned, and\n // a provisional key may still change at registration. Only a bare key is judged by its prefix.\n const isDataSourceTarget = injectedTarget\n ? isDataSourceClass(injectedTarget)\n : typeof injectKey === 'string' && injectKey.startsWith(`${BindingNamespaces.DATASOURCE}.`);\n\n if (!isDataSourceTarget) {\n throw getError({\n message: `[@repository][${target.name}] Invalid constructor | First parameter must be a DataSource | Found @inject with key: '${String(injectKey)}' | Expected a key starting with '${BindingNamespaces.DATASOURCE}.' or a DataSource class`,\n });\n }\n\n return;\n }\n\n // Checked only when this decorator writes the injection: an explicit @inject decides for itself.\n // An interface emits `Object` and a type-only class import emits `Function` under tsc (`Object`\n // under bun); neither names the class, so neither is judged.\n const firstParamType = Reflect.getMetadata('design:paramtypes', target)?.[0];\n if (firstParamType && firstParamType !== Object && firstParamType !== Function) {\n validateFirstConstructorParameter({ target, firstParamType, resolvedDataSource });\n }\n\n // The inherited list is the base repository's own, and setInjectMetadata may write straight into it.\n if (!ownInjects) {\n Reflect.defineMetadata(\n MetadataKeys.INJECT,\n [...(registry.getInjectMetadata({ target }) ?? [])],\n target,\n );\n }\n\n const derivedKey = BindingKeys.build({\n namespace: BindingNamespaces.DATASOURCE,\n key: typeof resolvedDataSource === 'string' ? resolvedDataSource : resolvedDataSource.name,\n });\n\n // The class first, decided when the repository is resolved: by then any registration - decorated,\n // `bindingList()`, or `dataSource(X, { binding })` - has recorded its key on the class. The derived\n // key is the fallback for a class nothing recorded, bound by hand under exactly that key.\n registry.setInjectMetadata({\n target,\n index: 0,\n metadata:\n typeof dataSourceRef === 'string'\n ? { key: derivedKey, index: 0, isOptional: false }\n : { target: dataSourceRef, key: derivedKey, index: 0, isOptional: false },\n });\n};\n\n/** Resolves repository metadata and registers bindings for schema auto-discovery. */\nconst resolveRepositoryMetadata = <\n Model extends AbstractEntity = AbstractEntity,\n DataSource extends IDataSource = IDataSource,\n>(opts: {\n metadata: TRepositoryMetadata<Model, DataSource>;\n target: Function;\n registry: MetadataRegistry;\n}): IResolvedRepositoryMetadata<Model, DataSource> => {\n const { metadata, target, registry } = opts;\n\n validateRepositoryMetadata({ metadata, target });\n\n const resolvedDataSource = resolveClass({ ref: metadata.dataSource });\n if (!resolvedDataSource) {\n throw getError({\n message: `[@repository][${target.name}] The dataSource resolver returned nothing at decoration time | An import cycle leaves the datasource class undefined here; import it without the cycle, or name it as a string`,\n });\n }\n\n // No model, so no binding: the datasource owns no schema through this repository.\n if (metadata.type === RepositoryTypes.REMOTE) {\n registerDataSourceInjection({\n target,\n registry,\n dataSourceRef: metadata.dataSource,\n resolvedDataSource,\n });\n return {\n type: RepositoryTypes.REMOTE,\n dataSource: resolvedDataSource,\n operationScope: metadata.operationScope,\n };\n }\n\n const resolvedModel = resolveValue({ value: metadata.model });\n\n registry.registerRepositoryBinding({\n repository: target,\n model: resolvedModel,\n dataSource: resolvedDataSource,\n });\n\n registerDataSourceInjection({\n target,\n registry,\n dataSourceRef: metadata.dataSource,\n resolvedDataSource,\n });\n\n return {\n type: RepositoryTypes.MODEL,\n model: resolvedModel,\n dataSource: resolvedDataSource,\n operationScope: metadata.operationScope,\n };\n};\n\n/** A bare `@repository()` on a subclass reuses the type, model and datasource its nearest decorated parent declared; the registration options (`binding`, `when`, ...) are never inherited, so the subclass registers under its own name. */\nconst inheritRepositoryMetadata = (opts: {\n target: Function;\n registry: MetadataRegistry;\n}): TRepositoryMetadata => {\n // Own metadata does not exist yet at decoration time, so this read walks the prototype chain.\n const inherited = opts.registry.getRepositoryMetadata({ target: opts.target });\n if (!inherited) {\n throw getError({\n message: `[@repository][${opts.target.name}] No metadata given and no decorated repository above it in the prototype chain | pass { model, dataSource } or decorate the parent`,\n });\n }\n\n if (inherited.type === RepositoryTypes.REMOTE) {\n const { type, dataSource, operationScope } = inherited;\n return { type, dataSource, operationScope };\n }\n\n const { type, model: parentModel, dataSource, operationScope } = inherited;\n return { type, model: parentModel, dataSource, operationScope };\n};\n\nconst applyRepositoryMetadata = <\n Model extends AbstractEntity = AbstractEntity,\n DataSource extends IDataSource = IDataSource,\n>(opts: {\n metadata: TRepositoryMetadata<Model, DataSource>;\n registration: IArtifactRegistrationOptions;\n target: Function;\n registry: MetadataRegistry;\n}): void => {\n const { metadata, registration, target, registry } = opts;\n injectable({\n type: ArtifactTypes.REPOSITORY,\n ...pickRegistrationOptions({ metadata: registration }),\n })(target);\n\n const resolved = resolveRepositoryMetadata({ metadata, target, registry });\n\n registry.setRepositoryMetadata({ target, metadata: { ...metadata, _resolved: resolved } });\n};\n\nexport const repository = <\n Model extends AbstractEntity = AbstractEntity,\n DataSource extends IDataSource = IDataSource,\n>(\n metadata?: TRepositoryMetadata<Model, DataSource>,\n): ClassDecorator => {\n return (target) => {\n const registry = MetadataRegistry.getInstance();\n if (!metadata) {\n applyRepositoryMetadata({\n metadata: inheritRepositoryMetadata({ target, registry }),\n registration: {},\n target,\n registry,\n });\n return;\n }\n\n applyRepositoryMetadata({ metadata, registration: metadata, target, registry });\n };\n};\n"]}
1
+ {"version":3,"file":"persistents.js","sourceRoot":"","sources":["../../../../src/base/metadata/persistents.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAStD,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACjG,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAC/E,OAAO,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAEvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAEnD,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAExD,oEAAoE;AACpE,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,QAAwB,EAAE,EAAkB,EAAE;IAClE,OAAO,CAAC,MAAM,EAAE,EAAE;QAChB,UAAU,CAAC;YACT,IAAI,EAAE,aAAa,CAAC,KAAK;YACzB,GAAG,iBAAiB,CAAC,uBAAuB,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;SAClE,CAAC,CAAC,MAAM,CAAC,CAAC;QAEX,MAAM,QAAQ,GAAG,oBAAoB,CAAC,sBAAsB,CAAC;YAC3D,KAAK,EAAE,MAAM,CAAC,IAAI;YAClB,QAAQ,EAAE,KAAK;SAChB,CAAC,CAAC;QAEH,oBAAoB,CAAC,4BAA4B,CAAC;YAChD,KAAK,EAAE,MAAM,CAAC,IAAI;YAClB,QAAQ,EAAE,QAAQ,CAAC,QAAQ;SAC5B,CAAC,CAAC;QACH,MAAM,EAAE,QAAQ,EAAE,GAAG,QAAQ,CAAC;QAE9B,MAAM,YAAY,GAAG,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC;QACrD,IAAI,YAAY,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,YAAY,CAAC,IAAI,YAAY,IAAI,CAAC,CAAC,EAAE,CAAC;YACzF,MAAM,QAAQ,CAAC;gBACb,OAAO,EAAE,WAAW,MAAM,CAAC,IAAI,wEAAwE,YAAY,EAAE;aACtH,CAAC,CAAC;QACL,CAAC;QAED,+FAA+F;QAC/F,4FAA4F;QAC5F,MAAM,QAAQ,GAAG,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,CAAC;QAC7C,IAAI,QAAQ,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,QAAQ,IAAI,CAAC,CAAC,EAAE,CAAC;YAC7E,MAAM,QAAQ,CAAC;gBACb,OAAO,EAAE,WAAW,MAAM,CAAC,IAAI,oEAAoE,QAAQ,EAAE;aAC9G,CAAC,CAAC;QACL,CAAC;QAED,kFAAkF;QAClF,MAAM,SAAS,GAAG,QAAQ,EAAE,SAAS,EAAE,SAAS,CAAC;QACjD,IAAI,SAAS,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,uBAAuB,CAAC,EAAE,CAAC;YAChE,MAAkC,CAAC,qBAAqB,GAAG,SAAS,CAAC;QACxE,CAAC;QAED,gBAAgB,CAAC,WAAW,EAAE,CAAC,aAAa,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;IACrE,CAAC,CAAC;AACJ,CAAC,CAAC;AAEF,sEAAsE;AACtE,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,QAA8B,EAAkB,EAAE;IAC3E,OAAO,CAAC,MAAM,EAAE,EAAE;QAChB,UAAU,CAAC;YACT,IAAI,EAAE,aAAa,CAAC,UAAU;YAC9B,GAAG,iBAAiB,CAAC,uBAAuB,CAAC,EAAE,QAAQ,EAAE,QAAQ,IAAI,EAAE,EAAE,CAAC;SAC3E,CAAC,CAAC,MAAM,CAAC,CAAC;QACX,gBAAgB,CAAC,WAAW,EAAE,CAAC,qBAAqB,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC7E,CAAC,CAAC;AACJ,CAAC,CAAC;AAEF,iKAAiK;AACjK,MAAM,0BAA0B,GAAG,CAGjC,IAGD,EAAQ,EAAE;IACT,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAClC,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,IAAI,eAAe,CAAC,KAAK,CAAC;IAEpD,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACnC,MAAM,QAAQ,CAAC;YACb,OAAO,EAAE,6CAA6C,MAAM,CAAC,IAAI,wCAAwC,IAAI,uBAAuB,CAAC,GAAG,eAAe,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;SACjL,CAAC,CAAC;IACL,CAAC;IAED,IAAI,IAAI,KAAK,eAAe,CAAC,KAAK,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QACtD,MAAM,QAAQ,CAAC;YACb,OAAO,EAAE,6CAA6C,MAAM,CAAC,IAAI,sCAAsC;SACxG,CAAC,CAAC;IACL,CAAC;IAED,IAAI,IAAI,KAAK,eAAe,CAAC,MAAM,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC;QACtD,MAAM,QAAQ,CAAC;YACb,OAAO,EAAE,6CAA6C,MAAM,CAAC,IAAI,2BAA2B,eAAe,CAAC,MAAM,+BAA+B;SAClJ,CAAC,CAAC;IACL,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC;QACzB,MAAM,QAAQ,CAAC;YACb,OAAO,EAAE,6CAA6C,MAAM,CAAC,IAAI,2CAA2C;SAC7G,CAAC,CAAC;IACL,CAAC;AACH,CAAC,CAAC;AAEF,oHAAoH;AACpH,MAAM,iCAAiC,GAAG,CAAC,IAI1C,EAAQ,EAAE;IACT,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,kBAAkB,EAAE,GAAG,IAAI,CAAC;IAE5D,6FAA6F;IAC7F,2FAA2F;IAC3F,MAAM,gBAAgB,GAAG,iBAAiB,CAAC,cAAc,CAAC,CAAC;IAE3D,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACtB,MAAM,QAAQ,CAAC;YACb,OAAO,EAAE,iBAAiB,MAAM,CAAC,IAAI,uFAAuF,cAAc,CAAC,IAAI,GAAG;SACnJ,CAAC,CAAC;IACL,CAAC;IAED,IAAI,OAAO,kBAAkB,KAAK,UAAU,EAAE,CAAC;QAC7C,OAAO;IACT,CAAC;IAED,MAAM,YAAY,GAChB,cAAc,KAAK,kBAAkB,IAAI,kBAAkB,CAAC,SAAS,YAAY,cAAc,CAAC;IAElG,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,MAAM,QAAQ,CAAC;YACb,OAAO,EAAE,iBAAiB,MAAM,CAAC,IAAI,gEAAgE,cAAc,CAAC,IAAI,gCAAgC,kBAAkB,CAAC,IAAI,GAAG;SACnL,CAAC,CAAC;IACL,CAAC;AACH,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,2BAA2B,GAAG,CAAC,IAKpC,EAAQ,EAAE;IACT,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE,kBAAkB,EAAE,GAAG,IAAI,CAAC;IAErE,+MAA+M;IAC/M,MAAM,UAAU,GAAkC,OAAO,CAAC,cAAc,CACtE,YAAY,CAAC,MAAM,EACnB,MAAM,CACP,CAAC;IACF,MAAM,cAAc,GAAG,UAAU,EAAE,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,CAAC,CAAC,CAAC;IAEvE,IAAI,cAAc,EAAE,CAAC;QACnB,8FAA8F;QAC9F,qFAAqF;QACrF,MAAM,cAAc,GAAG,cAAc,CAAC,MAAM;YAC1C,CAAC,CAAC,eAAe,CAAC,mBAAmB,CAAC,EAAE,MAAM,EAAE,cAAc,CAAC,MAAM,EAAE,CAAC;YACxE,CAAC,CAAC,SAAS,CAAC;QACd,MAAM,SAAS,GACb,cAAc,CAAC,GAAG;YAClB,CAAC,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QAEpF,8FAA8F;QAC9F,+FAA+F;QAC/F,MAAM,kBAAkB,GAAG,cAAc;YACvC,CAAC,CAAC,iBAAiB,CAAC,cAAc,CAAC;YACnC,CAAC,CAAC,OAAO,SAAS,KAAK,QAAQ,IAAI,SAAS,CAAC,UAAU,CAAC,GAAG,iBAAiB,CAAC,UAAU,GAAG,CAAC,CAAC;QAE9F,IAAI,CAAC,kBAAkB,EAAE,CAAC;YACxB,MAAM,QAAQ,CAAC;gBACb,OAAO,EAAE,iBAAiB,MAAM,CAAC,IAAI,2FAA2F,MAAM,CAAC,SAAS,CAAC,qCAAqC,iBAAiB,CAAC,UAAU,0BAA0B;aAC7O,CAAC,CAAC;QACL,CAAC;QAED,OAAO;IACT,CAAC;IAED,iGAAiG;IACjG,gGAAgG;IAChG,6DAA6D;IAC7D,MAAM,cAAc,GAAG,OAAO,CAAC,WAAW,CAAC,mBAAmB,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC7E,IAAI,cAAc,IAAI,cAAc,KAAK,MAAM,IAAI,cAAc,KAAK,QAAQ,EAAE,CAAC;QAC/E,iCAAiC,CAAC,EAAE,MAAM,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;IACpF,CAAC;IAED,qGAAqG;IACrG,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,CAAC,cAAc,CACpB,YAAY,CAAC,MAAM,EACnB,CAAC,GAAG,CAAC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,EACnD,MAAM,CACP,CAAC;IACJ,CAAC;IAED,MAAM,UAAU,GAAG,WAAW,CAAC,KAAK,CAAC;QACnC,SAAS,EAAE,iBAAiB,CAAC,UAAU;QACvC,GAAG,EAAE,OAAO,kBAAkB,KAAK,QAAQ,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,kBAAkB,CAAC,IAAI;KAC3F,CAAC,CAAC;IAEH,kGAAkG;IAClG,oGAAoG;IACpG,0FAA0F;IAC1F,QAAQ,CAAC,iBAAiB,CAAC;QACzB,MAAM;QACN,KAAK,EAAE,CAAC;QACR,QAAQ,EACN,OAAO,aAAa,KAAK,QAAQ;YAC/B,CAAC,CAAC,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE;YAClD,CAAC,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE;KAC9E,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,qFAAqF;AACrF,MAAM,yBAAyB,GAAG,CAGhC,IAID,EAAkD,EAAE;IACnD,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC;IAE5C,0BAA0B,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;IAEjD,MAAM,kBAAkB,GAAG,aAAa,CAAC,YAAY,CAAC,EAAE,GAAG,EAAE,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;IACpF,IAAI,CAAC,kBAAkB,EAAE,CAAC;QACxB,MAAM,QAAQ,CAAC;YACb,OAAO,EAAE,iBAAiB,MAAM,CAAC,IAAI,iLAAiL;SACvN,CAAC,CAAC;IACL,CAAC;IAED,kFAAkF;IAClF,IAAI,QAAQ,CAAC,IAAI,KAAK,eAAe,CAAC,MAAM,EAAE,CAAC;QAC7C,2BAA2B,CAAC;YAC1B,MAAM;YACN,QAAQ;YACR,aAAa,EAAE,QAAQ,CAAC,UAAU;YAClC,kBAAkB;SACnB,CAAC,CAAC;QACH,OAAO;YACL,IAAI,EAAE,eAAe,CAAC,MAAM;YAC5B,UAAU,EAAE,kBAAkB;YAC9B,cAAc,EAAE,QAAQ,CAAC,cAAc;SACxC,CAAC;IACJ,CAAC;IAED,MAAM,aAAa,GAAG,eAAe,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;IAE9E,QAAQ,CAAC,yBAAyB,CAAC;QACjC,UAAU,EAAE,MAAM;QAClB,KAAK,EAAE,aAAa;QACpB,UAAU,EAAE,kBAAkB;KAC/B,CAAC,CAAC;IAEH,2BAA2B,CAAC;QAC1B,MAAM;QACN,QAAQ;QACR,aAAa,EAAE,QAAQ,CAAC,UAAU;QAClC,kBAAkB;KACnB,CAAC,CAAC;IAEH,OAAO;QACL,IAAI,EAAE,eAAe,CAAC,KAAK;QAC3B,KAAK,EAAE,aAAa;QACpB,UAAU,EAAE,kBAAkB;QAC9B,cAAc,EAAE,QAAQ,CAAC,cAAc;KACxC,CAAC;AACJ,CAAC,CAAC;AAEF,6OAA6O;AAC7O,MAAM,yBAAyB,GAAG,CAAC,IAGlC,EAAuB,EAAE;IACxB,8FAA8F;IAC9F,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IAC/E,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,QAAQ,CAAC;YACb,OAAO,EAAE,iBAAiB,IAAI,CAAC,MAAM,CAAC,IAAI,qIAAqI;SAChL,CAAC,CAAC;IACL,CAAC;IAED,IAAI,SAAS,CAAC,IAAI,KAAK,eAAe,CAAC,MAAM,EAAE,CAAC;QAC9C,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,cAAc,EAAE,GAAG,SAAS,CAAC;QACvD,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,cAAc,EAAE,CAAC;IAC9C,CAAC;IAED,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,cAAc,EAAE,GAAG,SAAS,CAAC;IAC3E,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,cAAc,EAAE,CAAC;AAClE,CAAC,CAAC;AAEF,MAAM,uBAAuB,GAAG,CAG9B,IAKD,EAAQ,EAAE;IACT,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC;IAC1D,UAAU,CAAC;QACT,IAAI,EAAE,aAAa,CAAC,UAAU;QAC9B,GAAG,iBAAiB,CAAC,uBAAuB,CAAC,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;KACzE,CAAC,CAAC,MAAM,CAAC,CAAC;IAEX,MAAM,QAAQ,GAAG,yBAAyB,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;IAE3E,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,GAAG,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;AAC7F,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG,CAIxB,QAAiD,EACjC,EAAE;IAClB,OAAO,CAAC,MAAM,EAAE,EAAE;QAChB,MAAM,QAAQ,GAAG,gBAAgB,CAAC,WAAW,EAAE,CAAC;QAChD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,uBAAuB,CAAC;gBACtB,QAAQ,EAAE,yBAAyB,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;gBACzD,YAAY,EAAE,EAAE;gBAChB,MAAM;gBACN,QAAQ;aACT,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QAED,uBAAuB,CAAC,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;IAClF,CAAC,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import { BindingNamespaces } from '@/common/bindings';\nimport type {\n IArtifactRegistrationOptions,\n IDataSourceMetadata,\n IInjectMetadata,\n IModelMetadata,\n IResolvedRepositoryMetadata,\n TRepositoryMetadata,\n} from '@/helpers/inversion';\nimport { ArtifactTypes, BindingKeys, MetadataKeys, MetadataRegistry } from '@/helpers/inversion';\nimport { ClassResolver, ResolverUtility } from '@venizia/ignis-helpers/common';\nimport { getError } from '@venizia/ignis-helpers/core';\nimport type { IDataSource } from '../datasources';\nimport { isDataSourceClass } from '../datasources';\nimport type { AbstractEntity } from '../models';\nimport { RepositoryTypes } from '../repositories/common/constants';\nimport { injectable, InjectableUtility } from './injectable';\nimport { ModelMetadataUtility } from './model-metadata';\n\n/** Registers a model class with its static schema and relations. */\nexport const model = (input: IModelMetadata = {}): ClassDecorator => {\n return (target) => {\n injectable({\n type: ArtifactTypes.MODEL,\n ...InjectableUtility.pickRegistrationOptions({ metadata: input }),\n })(target);\n\n const metadata = ModelMetadataUtility.normalizeModelMetadata({\n model: target.name,\n metadata: input,\n });\n\n ModelMetadataUtility.assertNoRemovedModelSettings({\n model: target.name,\n settings: metadata.settings,\n });\n const { settings } = metadata;\n\n const defaultLimit = settings?.query?.limit?.default;\n if (defaultLimit !== undefined && (!Number.isInteger(defaultLimit) || defaultLimit <= 0)) {\n throw getError({\n message: `[model][${target.name}] Invalid 'query.limit.default' | Expected a positive integer | Got: ${defaultLimit}`,\n });\n }\n\n // Validated at DECORATION time, like the default limit: a bad ceiling is a wiring mistake, and\n // catching it at boot beats catching it on the one request that happens to reach the limit.\n const maxLimit = settings?.query?.limit?.max;\n if (maxLimit !== undefined && (!Number.isInteger(maxLimit) || maxLimit <= 0)) {\n throw getError({\n message: `[model][${target.name}] Invalid 'query.limit.max' | Expected a positive integer | Got: ${maxLimit}`,\n });\n }\n\n // Auto-populate AUTHORIZATION_SUBJECT from authorize.principal if not already set\n const principal = settings?.authorize?.principal;\n if (principal && !Object.hasOwn(target, 'AUTHORIZATION_SUBJECT')) {\n (target as Record<string, unknown>).AUTHORIZATION_SUBJECT = principal;\n }\n\n MetadataRegistry.getInstance().registerModel({ target, metadata });\n };\n};\n\n/** Registers a datasource with driver and auto-discovery settings. */\nexport const datasource = (metadata?: IDataSourceMetadata): ClassDecorator => {\n return (target) => {\n injectable({\n type: ArtifactTypes.DATASOURCE,\n ...InjectableUtility.pickRegistrationOptions({ metadata: metadata ?? {} }),\n })(target);\n MetadataRegistry.getInstance().setDataSourceMetadata({ target, metadata });\n };\n};\n\n/** Mirrors the `TRepositoryMetadata` union for JavaScript callers: a known type, a dataSource always, a model exactly when the type is RepositoryTypes.MODEL. */\nconst validateRepositoryMetadata = <\n Model extends AbstractEntity = AbstractEntity,\n DataSource extends IDataSource = IDataSource,\n>(opts: {\n metadata: TRepositoryMetadata<Model, DataSource>;\n target: Function;\n}): void => {\n const { metadata, target } = opts;\n const type = metadata.type ?? RepositoryTypes.MODEL;\n\n if (!RepositoryTypes.isValid(type)) {\n throw getError({\n message: `[validateRepositoryMetadata][@repository][${target.name}] Invalid metadata | Unknown 'type': ${type} | Expected one of: ${[...RepositoryTypes.SCHEME_SET].join(', ')}`,\n });\n }\n\n if (type === RepositoryTypes.MODEL && !metadata.model) {\n throw getError({\n message: `[validateRepositoryMetadata][@repository][${target.name}] Invalid metadata | Missing 'model'`,\n });\n }\n\n if (type === RepositoryTypes.REMOTE && metadata.model) {\n throw getError({\n message: `[validateRepositoryMetadata][@repository][${target.name}] Invalid metadata | A '${RepositoryTypes.REMOTE}' repository takes no 'model'`,\n });\n }\n\n if (!metadata.dataSource) {\n throw getError({\n message: `[validateRepositoryMetadata][@repository][${target.name}] Invalid metadata | Missing 'dataSource'`,\n });\n }\n};\n\n/** Asserts the constructor's first parameter is an AbstractDataSource compatible with what @repository declared. */\nconst validateFirstConstructorParameter = (opts: {\n target: Function;\n firstParamType: Function;\n resolvedDataSource: string | Function;\n}): void => {\n const { target, firstParamType, resolvedDataSource } = opts;\n\n // NOT `instanceof`: two copies of this package give two `AbstractDataSource` classes and the\n // check would be false across them, rejecting a perfectly valid repository at import time.\n const isDataSourceType = isDataSourceClass(firstParamType);\n\n if (!isDataSourceType) {\n throw getError({\n message: `[@repository][${target.name}] Invalid constructor | First parameter must extend AbstractDataSource | Received: '${firstParamType.name}'`,\n });\n }\n\n if (typeof resolvedDataSource !== 'function') {\n return;\n }\n\n const isCompatible =\n firstParamType === resolvedDataSource || resolvedDataSource.prototype instanceof firstParamType;\n\n if (!isCompatible) {\n throw getError({\n message: `[@repository][${target.name}] Invalid constructor | Type mismatch | Constructor expects '${firstParamType.name}' but @repository specifies '${resolvedDataSource.name}'`,\n });\n }\n};\n\n/**\n * Auto-injects dataSource at constructor param[0] unless explicit @inject exists. A class is injected\n * by the class itself, so the container reads the key its registration recorded: a pinned\n * `binding` and a minified class name both resolve. Only a string reference is a key.\n */\nconst registerDataSourceInjection = (opts: {\n target: Function;\n registry: MetadataRegistry;\n dataSourceRef: TRepositoryMetadata['dataSource'];\n resolvedDataSource: string | Function;\n}): void => {\n const { target, registry, dataSourceRef, resolvedDataSource } = opts;\n\n // Own metadata only: `getInjectMetadata` walks the prototype chain, so a repository extending another @repository class would see the BASE's injection at param[0] and silently resolve the base's dataSource.\n const ownInjects: IInjectMetadata[] | undefined = Reflect.getOwnMetadata(\n MetadataKeys.INJECT,\n target,\n );\n const injectAtIndex0 = ownInjects?.find((entry) => entry?.index === 0);\n\n if (injectAtIndex0) {\n // `@inject({ target })` carries no key; read the one recorded on the class. The function form\n // resolves through the same helper the container uses, so both paths read one class.\n const injectedTarget = injectAtIndex0.target\n ? ResolverUtility.resolveInjectTarget({ target: injectAtIndex0.target })\n : undefined;\n const injectKey =\n injectAtIndex0.key ??\n (injectedTarget ? registry.getBindingKey({ target: injectedTarget }) : undefined);\n\n // A class is judged by its brand: its key may sit under any namespace a `binding` pinned, and\n // a provisional key may still change at registration. Only a bare key is judged by its prefix.\n const isDataSourceTarget = injectedTarget\n ? isDataSourceClass(injectedTarget)\n : typeof injectKey === 'string' && injectKey.startsWith(`${BindingNamespaces.DATASOURCE}.`);\n\n if (!isDataSourceTarget) {\n throw getError({\n message: `[@repository][${target.name}] Invalid constructor | First parameter must be a DataSource | Found @inject with key: '${String(injectKey)}' | Expected a key starting with '${BindingNamespaces.DATASOURCE}.' or a DataSource class`,\n });\n }\n\n return;\n }\n\n // Checked only when this decorator writes the injection: an explicit @inject decides for itself.\n // An interface emits `Object` and a type-only class import emits `Function` under tsc (`Object`\n // under bun); neither names the class, so neither is judged.\n const firstParamType = Reflect.getMetadata('design:paramtypes', target)?.[0];\n if (firstParamType && firstParamType !== Object && firstParamType !== Function) {\n validateFirstConstructorParameter({ target, firstParamType, resolvedDataSource });\n }\n\n // The inherited list is the base repository's own, and setInjectMetadata may write straight into it.\n if (!ownInjects) {\n Reflect.defineMetadata(\n MetadataKeys.INJECT,\n [...(registry.getInjectMetadata({ target }) ?? [])],\n target,\n );\n }\n\n const derivedKey = BindingKeys.build({\n namespace: BindingNamespaces.DATASOURCE,\n key: typeof resolvedDataSource === 'string' ? resolvedDataSource : resolvedDataSource.name,\n });\n\n // The class first, decided when the repository is resolved: by then any registration - decorated,\n // `bindingList()`, or `dataSource(X, { binding })` - has recorded its key on the class. The derived\n // key is the fallback for a class nothing recorded, bound by hand under exactly that key.\n registry.setInjectMetadata({\n target,\n index: 0,\n metadata:\n typeof dataSourceRef === 'string'\n ? { key: derivedKey, index: 0, isOptional: false }\n : { target: dataSourceRef, key: derivedKey, index: 0, isOptional: false },\n });\n};\n\n/** Resolves repository metadata and registers bindings for schema auto-discovery. */\nconst resolveRepositoryMetadata = <\n Model extends AbstractEntity = AbstractEntity,\n DataSource extends IDataSource = IDataSource,\n>(opts: {\n metadata: TRepositoryMetadata<Model, DataSource>;\n target: Function;\n registry: MetadataRegistry;\n}): IResolvedRepositoryMetadata<Model, DataSource> => {\n const { metadata, target, registry } = opts;\n\n validateRepositoryMetadata({ metadata, target });\n\n const resolvedDataSource = ClassResolver.resolveClass({ ref: metadata.dataSource });\n if (!resolvedDataSource) {\n throw getError({\n message: `[@repository][${target.name}] The dataSource resolver returned nothing at decoration time | An import cycle leaves the datasource class undefined here; import it without the cycle, or name it as a string`,\n });\n }\n\n // No model, so no binding: the datasource owns no schema through this repository.\n if (metadata.type === RepositoryTypes.REMOTE) {\n registerDataSourceInjection({\n target,\n registry,\n dataSourceRef: metadata.dataSource,\n resolvedDataSource,\n });\n return {\n type: RepositoryTypes.REMOTE,\n dataSource: resolvedDataSource,\n operationScope: metadata.operationScope,\n };\n }\n\n const resolvedModel = ResolverUtility.resolveValue({ value: metadata.model });\n\n registry.registerRepositoryBinding({\n repository: target,\n model: resolvedModel,\n dataSource: resolvedDataSource,\n });\n\n registerDataSourceInjection({\n target,\n registry,\n dataSourceRef: metadata.dataSource,\n resolvedDataSource,\n });\n\n return {\n type: RepositoryTypes.MODEL,\n model: resolvedModel,\n dataSource: resolvedDataSource,\n operationScope: metadata.operationScope,\n };\n};\n\n/** A bare `@repository()` on a subclass reuses the type, model and datasource its nearest decorated parent declared; the registration options (`binding`, `when`, ...) are never inherited, so the subclass registers under its own name. */\nconst inheritRepositoryMetadata = (opts: {\n target: Function;\n registry: MetadataRegistry;\n}): TRepositoryMetadata => {\n // Own metadata does not exist yet at decoration time, so this read walks the prototype chain.\n const inherited = opts.registry.getRepositoryMetadata({ target: opts.target });\n if (!inherited) {\n throw getError({\n message: `[@repository][${opts.target.name}] No metadata given and no decorated repository above it in the prototype chain | pass { model, dataSource } or decorate the parent`,\n });\n }\n\n if (inherited.type === RepositoryTypes.REMOTE) {\n const { type, dataSource, operationScope } = inherited;\n return { type, dataSource, operationScope };\n }\n\n const { type, model: parentModel, dataSource, operationScope } = inherited;\n return { type, model: parentModel, dataSource, operationScope };\n};\n\nconst applyRepositoryMetadata = <\n Model extends AbstractEntity = AbstractEntity,\n DataSource extends IDataSource = IDataSource,\n>(opts: {\n metadata: TRepositoryMetadata<Model, DataSource>;\n registration: IArtifactRegistrationOptions;\n target: Function;\n registry: MetadataRegistry;\n}): void => {\n const { metadata, registration, target, registry } = opts;\n injectable({\n type: ArtifactTypes.REPOSITORY,\n ...InjectableUtility.pickRegistrationOptions({ metadata: registration }),\n })(target);\n\n const resolved = resolveRepositoryMetadata({ metadata, target, registry });\n\n registry.setRepositoryMetadata({ target, metadata: { ...metadata, _resolved: resolved } });\n};\n\nexport const repository = <\n Model extends AbstractEntity = AbstractEntity,\n DataSource extends IDataSource = IDataSource,\n>(\n metadata?: TRepositoryMetadata<Model, DataSource>,\n): ClassDecorator => {\n return (target) => {\n const registry = MetadataRegistry.getInstance();\n if (!metadata) {\n applyRepositoryMetadata({\n metadata: inheritRepositoryMetadata({ target, registry }),\n registration: {},\n target,\n registry,\n });\n return;\n }\n\n applyRepositoryMetadata({ metadata, registration: metadata, target, registry });\n };\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../../../../src/base/metadata/routes/controller.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAI/D,eAAO,MAAM,UAAU,GAAI,UAAU,mBAAmB,KAAG,cAO1D,CAAC"}
1
+ {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../../../../src/base/metadata/routes/controller.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAI/D,eAAO,MAAM,UAAU,GAAI,UAAU,mBAAmB,KAAG,cAQ1D,CAAC"}
@@ -1,8 +1,11 @@
1
1
  import { ArtifactTypes, MetadataRegistry } from '../../../helpers/inversion/index.js';
2
- import { injectable, pickRegistrationOptions } from '../injectable.js';
2
+ import { injectable, InjectableUtility } from '../injectable.js';
3
3
  export const controller = (metadata) => {
4
4
  return (target) => {
5
- injectable({ type: ArtifactTypes.CONTROLLER, ...pickRegistrationOptions({ metadata }) })(target);
5
+ injectable({
6
+ type: ArtifactTypes.CONTROLLER,
7
+ ...InjectableUtility.pickRegistrationOptions({ metadata }),
8
+ })(target);
6
9
  MetadataRegistry.getInstance().setControllerMetadata({ target, metadata });
7
10
  };
8
11
  };
@@ -1 +1 @@
1
- {"version":3,"file":"controller.js","sourceRoot":"","sources":["../../../../../src/base/metadata/routes/controller.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACtE,OAAO,EAAE,UAAU,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAEpE,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,QAA6B,EAAkB,EAAE;IAC1E,OAAO,CAAC,MAAM,EAAE,EAAE;QAChB,UAAU,CAAC,EAAE,IAAI,EAAE,aAAa,CAAC,UAAU,EAAE,GAAG,uBAAuB,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,CACtF,MAAM,CACP,CAAC;QACF,gBAAgB,CAAC,WAAW,EAAE,CAAC,qBAAqB,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC7E,CAAC,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import type { TControllerMetadata } from '@/helpers/inversion';\nimport { ArtifactTypes, MetadataRegistry } from '@/helpers/inversion';\nimport { injectable, pickRegistrationOptions } from '../injectable';\n\nexport const controller = (metadata: TControllerMetadata): ClassDecorator => {\n return (target) => {\n injectable({ type: ArtifactTypes.CONTROLLER, ...pickRegistrationOptions({ metadata }) })(\n target,\n );\n MetadataRegistry.getInstance().setControllerMetadata({ target, metadata });\n };\n};\n"]}
1
+ {"version":3,"file":"controller.js","sourceRoot":"","sources":["../../../../../src/base/metadata/routes/controller.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACtE,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAE9D,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,QAA6B,EAAkB,EAAE;IAC1E,OAAO,CAAC,MAAM,EAAE,EAAE;QAChB,UAAU,CAAC;YACT,IAAI,EAAE,aAAa,CAAC,UAAU;YAC9B,GAAG,iBAAiB,CAAC,uBAAuB,CAAC,EAAE,QAAQ,EAAE,CAAC;SAC3D,CAAC,CAAC,MAAM,CAAC,CAAC;QACX,gBAAgB,CAAC,WAAW,EAAE,CAAC,qBAAqB,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC7E,CAAC,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import type { TControllerMetadata } from '@/helpers/inversion';\nimport { ArtifactTypes, MetadataRegistry } from '@/helpers/inversion';\nimport { injectable, InjectableUtility } from '../injectable';\n\nexport const controller = (metadata: TControllerMetadata): ClassDecorator => {\n return (target) => {\n injectable({\n type: ArtifactTypes.CONTROLLER,\n ...InjectableUtility.pickRegistrationOptions({ metadata }),\n })(target);\n MetadataRegistry.getInstance().setControllerMetadata({ target, metadata });\n };\n};\n"]}
@@ -1,9 +1,9 @@
1
1
  import { BaseHelper, EnvironmentNames, LogLevels, MessageCode, MessageTemplate, } from '@venizia/ignis-helpers/core';
2
- import { HTTP, toJsonSafe } from '@venizia/ignis-helpers/common';
2
+ import { HTTP, RedactUtility } from '@venizia/ignis-helpers/common';
3
3
  import { REQUEST_ID_KEY } from '../common/index.js';
4
- import { isDatabaseClientError, isRetryableDatabaseError } from './database.handler.js';
4
+ import { DatabaseErrorHandler } from './database.handler.js';
5
5
  import { ApplicationErrorTypes, DATABASE_RETRYABLE_ERROR_CODE, DATABASE_RETRYABLE_ERROR_MESSAGE, } from './definition.js';
6
- import { formatZodError } from './zod.handler.js';
6
+ import { ZodErrorHandler } from './zod.handler.js';
7
7
  const DEFAULT_INTERNAL_ERROR_MESSAGE = 'Internal Server Error';
8
8
  /** An intentional error's throw site is still worth naming; its caller chain is framework plumbing, so it gets a smaller budget than an unexpected one. */
9
9
  const DEFAULT_INTENTIONAL_STACK_FRAMES = 5;
@@ -26,7 +26,7 @@ const renderValue = (opts) => {
26
26
  if (typeof value === 'string') {
27
27
  return value;
28
28
  }
29
- const safe = toJsonSafe({ value });
29
+ const safe = RedactUtility.toJsonSafe({ value });
30
30
  try {
31
31
  return JSON.stringify(safe) ?? String(value);
32
32
  }
@@ -128,7 +128,7 @@ export class BaseAppErrorMiddleware extends BaseHelper {
128
128
  if (dbError.isClientError) {
129
129
  return ApplicationErrorTypes.DATABASE_CLIENT;
130
130
  }
131
- if (isRetryableDatabaseError({ error })) {
131
+ if (DatabaseErrorHandler.isRetryableDatabaseError({ error })) {
132
132
  return ApplicationErrorTypes.DATABASE_RETRYABLE;
133
133
  }
134
134
  if ('statusCode' in error || this.readClientErrorStatus({ error }) !== undefined) {
@@ -167,7 +167,7 @@ export class BaseAppErrorMiddleware extends BaseHelper {
167
167
  }
168
168
  resolve(opts) {
169
169
  const { error, isProduction } = opts;
170
- const dbError = isDatabaseClientError({ error, isProduction });
170
+ const dbError = DatabaseErrorHandler.isDatabaseClientError({ error, isProduction });
171
171
  const type = this.classify({ error, dbError });
172
172
  switch (type) {
173
173
  case ApplicationErrorTypes.DATABASE_CLIENT: {
@@ -251,7 +251,7 @@ export class BaseAppErrorMiddleware extends BaseHelper {
251
251
  const requestId = context.get(REQUEST_ID_KEY);
252
252
  const isProduction = this.isProduction({ context, error, requestId });
253
253
  if (error.name === 'ZodError') {
254
- const rs = formatZodError({
254
+ const rs = ZodErrorHandler.formatZodError({
255
255
  isProduction,
256
256
  requestId,
257
257
  url: context.req.url,
@@ -1 +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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","sourcesContent":["import type { ILogger, TLogLevel } from '@venizia/ignis-helpers/core';\nimport type { TNullable } from '@venizia/ignis-helpers/common';\nimport {\n BaseHelper,\n EnvironmentNames,\n LogLevels,\n MessageCode,\n MessageTemplate,\n} from '@venizia/ignis-helpers/core';\nimport { HTTP, toJsonSafe } from '@venizia/ignis-helpers/common';\nimport type { IProvider } from '@venizia/ignis-inversion';\nimport type { Context } from 'hono';\nimport type { ErrorHandler, HTTPResponseError } from 'hono/types';\nimport { REQUEST_ID_KEY } from '../common';\nimport { isDatabaseClientError, isRetryableDatabaseError } from './database.handler';\nimport {\n ApplicationErrorTypes,\n DATABASE_RETRYABLE_ERROR_CODE,\n DATABASE_RETRYABLE_ERROR_MESSAGE,\n} from './definition';\nimport type { IResolvedApplicationError, TApplicationErrorType } from './common';\nimport { formatZodError } from './zod.handler';\n\nconst DEFAULT_INTERNAL_ERROR_MESSAGE = 'Internal Server Error';\n\n/** An intentional error's throw site is still worth naming; its caller chain is framework plumbing, so it gets a smaller budget than an unexpected one. */\nconst DEFAULT_INTENTIONAL_STACK_FRAMES = 5;\nconst DEFAULT_UNEXPECTED_STACK_FRAMES = 10;\n\n/** How a thrown error is rendered into the log line. Must never throw - a throw inside the error handler turns a handled failure into an unhandled one. */\nexport type TErrorLogFormatter = (opts: {\n error: unknown;\n messageCode?: string;\n extra?: Record<string, unknown>;\n includeStack?: boolean;\n maxStackFrames?: number;\n}) => string;\n\ntype TThrown = Error | HTTPResponseError;\ntype TDatabaseClientError = ReturnType<typeof isDatabaseClientError>;\n\n/**\n * Renders a value into one log-safe fragment.\n *\n * Redaction is not optional here. This runs on `extra`, which is whatever a throw site chose to\n * attach - `getError({ extra: { apiKey } })` is a shape applications write - and in a Worker this\n * fragment lands in the browser console. `toJsonSafe` masks secret-shaped keys; a hand-rolled\n * `JSON.stringify` does not, and the server path has always redacted.\n *\n * The BigInt replacer stays: `toJsonSafe` leaves BigInt intact and `JSON.stringify` refuses it, so\n * without this a single BigInt would collapse the whole fragment to the marker below. Anything else\n * it refuses yields that marker rather than a throw - this is the last-resort error handler, where a\n * throw turns a handled failure into an unhandled one.\n */\nconst renderValue = (opts: { value: unknown }): string => {\n const { value } = opts;\n\n if (typeof value === 'string') {\n return value;\n }\n\n const safe = toJsonSafe({ value });\n\n try {\n return JSON.stringify(safe) ?? String(value);\n } catch {\n // A replacer is 6x the cost of plain stringify and deopts every key, so it is installed only\n // once BigInt has actually thrown - the case it exists for, and the rare one.\n try {\n const rendered = JSON.stringify(safe, (_key, entry: unknown) =>\n typeof entry === 'bigint' ? entry.toString() : entry,\n );\n\n return rendered ?? String(value);\n } catch {\n // Not a swallowed failure: this marker IS the report, and it lands in the log line the caller\n // is building.\n return '[unrenderable]';\n }\n }\n};\n\n/**\n * Hono `onError`: ZodError -> 422, DB client error -> 400, retryable conflict -> 409, `getError` ->\n * its own status, else 500. Browser-pure: the two reads that need a host - the ambient environment\n * name and the error formatter - are constructor OPTIONS, not methods to subclass.\n *\n * They were hooks once, and three subclasses existed to answer them and nothing else. A class seam\n * is also unreachable from application code, so the browser example had to fake the environment with\n * a Hono middleware assigning `context.env`. `@venizia/ignis`'s `AppErrorMiddleware` now just\n * supplies `process.env.NODE_ENV` and `ErrorPrettier` as options.\n */\nexport class BaseAppErrorMiddleware extends BaseHelper implements IProvider<ErrorHandler> {\n private rootKey: TNullable<string>;\n private intentionalStackFrames: number;\n private unexpectedStackFrames: number;\n\n /**\n * How this host reads its ambient environment name, and the ONE option that says whether it has\n * one at all: absent means it does not (a browser), so an unresolved name is by design; present\n * but returning `undefined` means a host that should have one is misconfigured. Either way\n * {@link isProduction} fails closed.\n *\n * A function, not a string: `process.env.NODE_ENV` has to be read per request, since a test - and\n * a `--env-file` reload - can change it after the middleware is built.\n */\n private readonly environment?: () => string | undefined;\n\n /** Replaces {@link renderErrorForLog} - `@venizia/ignis` passes `ErrorPrettier`, which reaches `node:util` and so cannot live here. */\n private readonly formatErrorOverride?: TErrorLogFormatter;\n\n constructor(opts?: {\n logger?: ILogger;\n rootKey?: string;\n intentionalStackFrames?: number;\n unexpectedStackFrames?: number;\n environment?: () => string | undefined;\n formatError?: TErrorLogFormatter;\n }) {\n // `new.target`, not a literal: a subclass logs under its own name, so `@venizia/ignis`'s\n // `AppErrorMiddleware` keeps the scope it has always logged under.\n super({ scope: new.target.name });\n\n this.rootKey = opts?.rootKey;\n this.intentionalStackFrames = opts?.intentionalStackFrames ?? DEFAULT_INTENTIONAL_STACK_FRAMES;\n this.unexpectedStackFrames = opts?.unexpectedStackFrames ?? DEFAULT_UNEXPECTED_STACK_FRAMES;\n this.environment = opts?.environment;\n this.formatErrorOverride = opts?.formatError;\n\n if (opts?.logger) {\n this.logger = opts.logger;\n }\n }\n\n /** Renders a thrown error for the log, through the `formatError` option when one was given. */\n protected formatError(opts: {\n error: unknown;\n messageCode?: string;\n extra?: Record<string, unknown>;\n includeStack?: boolean;\n maxStackFrames?: number;\n }): string {\n return (this.formatErrorOverride ?? ((o) => this.renderErrorForLog(o)))(opts);\n }\n\n /**\n * The default log rendering: pure and deliberately small, so the whole middleware stays\n * browser-pure.\n *\n * Must never throw, cycles included: a throw inside the error handler turns a handled failure\n * into an unhandled one.\n */\n private renderErrorForLog(opts: {\n error: unknown;\n messageCode?: string;\n extra?: Record<string, unknown>;\n includeStack?: boolean;\n maxStackFrames?: number;\n }): string {\n const { error, messageCode, extra, includeStack = true, maxStackFrames } = opts;\n const thrown = error as Partial<Error> | null | undefined;\n const lines: Array<string> = [];\n\n if (typeof thrown?.name === 'string') {\n lines.push(`name: ${thrown.name}`);\n }\n\n lines.push(\n `message: ${typeof thrown?.message === 'string' ? thrown.message : renderValue({ value: error })}`,\n );\n\n if (messageCode) {\n lines.push(`code: ${messageCode}`);\n }\n\n if (extra && Object.keys(extra).length > 0) {\n lines.push(`extra: ${renderValue({ value: extra })}`);\n }\n\n if (includeStack && typeof thrown?.stack === 'string') {\n const frames = thrown.stack.split('\\n').filter((line) => line.trimStart().startsWith('at '));\n const capped = maxStackFrames === undefined ? frames : frames.slice(0, maxStackFrames);\n\n if (capped.length > 0) {\n lines.push(`stack:\\n${capped.join('\\n')}`);\n }\n }\n\n return lines.map((line) => `- ${line}`).join('\\n');\n }\n\n private withRootKey(payload: object) {\n return this.rootKey ? { [this.rootKey]: payload } : payload;\n }\n\n /** Fail-closed: an unset or unrecognized env is production. */\n private isProduction(opts: { context: Context; error: TThrown; requestId: string }): boolean {\n const { context, error, requestId } = opts;\n const env = [context.env?.NODE_ENV, this.environment?.()].find(Boolean);\n\n if (!env) {\n // Only a host that HAS an ambient environment can be misconfigured about it. In a browser the\n // absence is by design, and shouting it at error level on every request buries the error the\n // reader is actually looking at. Both paths still sanitize.\n if (this.environment) {\n this.logger.error(\n '[%s] INVALID ENV IDENTIFIER | env: %s | path: %s | method: %s | url: %s\\n%s',\n requestId,\n env,\n context.req.path,\n context.req.method,\n context.req.url,\n this.formatError({ error }),\n );\n } else {\n this.logger.debug(\n '[%s] No ambient environment - sanitizing as production | path: %s | set NODE_ENV on the Hono env binding to opt out',\n requestId,\n context.req.path,\n );\n }\n\n return true;\n }\n\n return !EnvironmentNames.DEVELOPMENT_ENVS.has(env.toLowerCase());\n }\n\n private classify(opts: { error: TThrown; dbError: TDatabaseClientError }): TApplicationErrorType {\n const { error, dbError } = opts;\n\n if (dbError.isClientError) {\n return ApplicationErrorTypes.DATABASE_CLIENT;\n }\n\n if (isRetryableDatabaseError({ error })) {\n return ApplicationErrorTypes.DATABASE_RETRYABLE;\n }\n\n if ('statusCode' in error || this.readClientErrorStatus({ error }) !== undefined) {\n return ApplicationErrorTypes.INTENTIONAL;\n }\n\n return ApplicationErrorTypes.UNEXPECTED;\n }\n\n /** Hono's `HTTPException` carries `status`, not `statusCode`. Only a 4xx is the caller's fault; a 5xx stays unexpected, so its message is sanitized. */\n private readClientErrorStatus(opts: { error: TThrown }): number | undefined {\n const { error } = opts;\n\n if (!('getResponse' in error) || !('status' in error) || typeof error.status !== 'number') {\n return undefined;\n }\n\n const isClientError =\n error.status >= HTTP.ResultCodes.RS_4.BadRequest &&\n error.status < HTTP.ResultCodes.RS_5.InternalServerError;\n\n return isClientError ? error.status : undefined;\n }\n\n /** `getError` sets `statusCode`, and it wins when a foreign error carries both. Neither usable is a 500. */\n private readIntentionalStatus(opts: { error: TThrown }): number {\n const { error } = opts;\n\n if ('statusCode' in error && typeof error.statusCode === 'number') {\n return error.statusCode;\n }\n\n return this.readClientErrorStatus({ error }) ?? HTTP.ResultCodes.RS_5.InternalServerError;\n }\n\n /** An ApplicationError's `normalized` is authoritative - a `transform` may have reworded `text`. */\n private build(opts: {\n error: TThrown;\n statusCode: number;\n message: string;\n type: TApplicationErrorType;\n messageCode?: string;\n }): IResolvedApplicationError {\n const { error, statusCode, message, type, messageCode } = opts;\n\n // Fallback for a FOREIGN error that sets its own code; an ApplicationError reports via `normalized`.\n const code =\n messageCode ??\n MessageCode.resolve('messageCode' in error ? (error.messageCode as string) : undefined);\n\n const normalized =\n 'normalized' in error\n ? (error.normalized as IResolvedApplicationError['normalized'])\n : { text: message, code, args: {} };\n\n return { statusCode, message, normalized, type };\n }\n\n private resolve(opts: { error: TThrown; isProduction: boolean }): IResolvedApplicationError {\n const { error, isProduction } = opts;\n const dbError = isDatabaseClientError({ error, isProduction });\n const type = this.classify({ error, dbError });\n\n switch (type) {\n case ApplicationErrorTypes.DATABASE_CLIENT: {\n return this.build({\n error,\n type,\n statusCode: HTTP.ResultCodes.RS_4.BadRequest,\n // The fallback is unreachable today; it keeps the driver's raw text from ever surfacing.\n message: dbError.message ?? DEFAULT_INTERNAL_ERROR_MESSAGE,\n });\n }\n\n case ApplicationErrorTypes.DATABASE_RETRYABLE: {\n return this.build({\n error,\n type,\n statusCode: HTTP.ResultCodes.RS_4.Conflict,\n message: DATABASE_RETRYABLE_ERROR_MESSAGE,\n messageCode: DATABASE_RETRYABLE_ERROR_CODE,\n });\n }\n\n case ApplicationErrorTypes.INTENTIONAL: {\n return this.build({\n error,\n type,\n statusCode: this.readIntentionalStatus({ error }),\n message: error.message,\n });\n }\n\n default: {\n return this.build({\n error,\n type: ApplicationErrorTypes.UNEXPECTED,\n statusCode: HTTP.ResultCodes.RS_5.InternalServerError,\n // Never leak a raw message - it may carry SQL, schema names or connection details.\n message: isProduction ? DEFAULT_INTERNAL_ERROR_MESSAGE : error.message,\n });\n }\n }\n }\n\n /** A throw site may set `logLevel` via `getError`; anything unset or malformed logs at `error`. */\n private resolveLogLevel(opts: { error: TThrown }): TLogLevel {\n const candidate = (opts.error as { logLevel?: unknown }).logLevel;\n\n if (typeof candidate === 'string' && LogLevels.isValid(candidate)) {\n return candidate as TLogLevel;\n }\n\n return LogLevels.ERROR;\n }\n\n /** The one place a thrown error reaches the log - called once the status is known, so it carries it. */\n private logError(opts: {\n error: TThrown;\n context: Context;\n requestId: string;\n statusCode: number;\n messageCode: string;\n type?: TApplicationErrorType;\n }) {\n const { error, context, requestId, statusCode, messageCode, type } = opts;\n\n this.logger.log(\n this.resolveLogLevel({ error }),\n '[%s] REQUEST ERROR | %s | %s %s\\n%s',\n requestId,\n statusCode,\n context.req.method,\n context.req.url,\n this.formatError({\n error,\n // The default code means \"no code\" - logging it on every error would be a noise line.\n messageCode: messageCode === MessageCode.DEFAULT ? undefined : messageCode,\n extra: 'extra' in error ? (error.extra as Record<string, unknown>) : undefined,\n includeStack: true,\n // An intentional error still needs its throw site; it just does not need the caller chain behind it.\n maxStackFrames:\n type === ApplicationErrorTypes.UNEXPECTED\n ? this.unexpectedStackFrames\n : this.intentionalStackFrames,\n }),\n );\n }\n\n /** Only an intentional error's message is a catalog template; every other branch writes its own text, so it passes through as is. */\n private renderMessage(opts: {\n resolved: IResolvedApplicationError;\n isProduction: boolean;\n requestId: string;\n }): string {\n const { resolved, isProduction, requestId } = opts;\n\n if (resolved.type !== ApplicationErrorTypes.INTENTIONAL) {\n return resolved.message;\n }\n\n const { text, missing } = MessageTemplate.render({\n text: resolved.message,\n args: resolved.normalized.args,\n });\n\n // Production stays silent and renders what it can; anywhere else a missing arg is a throw site to fix.\n if (missing.length > 0 && !isProduction) {\n this.logger.warn(\n '[%s] MESSAGE PLACEHOLDER WITHOUT ARG | code: %s | keys: %s',\n requestId,\n resolved.normalized.code,\n missing.join(', '),\n );\n }\n\n return text;\n }\n\n value(): ErrorHandler {\n return async (error, context) => {\n const requestId = context.get(REQUEST_ID_KEY);\n const isProduction = this.isProduction({ context, error, requestId });\n\n if (error.name === 'ZodError') {\n const rs = formatZodError({\n isProduction,\n requestId,\n url: context.req.url,\n path: context.req.path,\n error,\n });\n\n this.logError({\n error,\n context,\n requestId,\n statusCode: rs.statusCode,\n messageCode: rs.response.normalized.code,\n });\n\n return context.json(\n this.withRootKey(rs.response),\n rs.statusCode as Parameters<typeof context.json>[1],\n );\n }\n\n const resolved = this.resolve({ error, isProduction });\n const { statusCode, normalized, type } = resolved;\n\n this.logError({ error, context, requestId, statusCode, messageCode: normalized.code, type });\n\n const rs = {\n message: this.renderMessage({ resolved, isProduction, requestId }),\n statusCode,\n normalized,\n requestId,\n extra: 'extra' in error ? error?.extra : undefined,\n details: {\n url: context.req.url,\n path: context.req.path,\n stack: !isProduction ? error.stack : undefined,\n cause: !isProduction ? error.cause : undefined,\n },\n };\n\n return context.json(this.withRootKey(rs), statusCode as Parameters<typeof context.json>[1]);\n };\n }\n}\n"]}
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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","sourcesContent":["import type { ILogger, TLogLevel } from '@venizia/ignis-helpers/core';\nimport type { TNullable } from '@venizia/ignis-helpers/common';\nimport {\n BaseHelper,\n EnvironmentNames,\n LogLevels,\n MessageCode,\n MessageTemplate,\n} from '@venizia/ignis-helpers/core';\nimport { HTTP, RedactUtility } from '@venizia/ignis-helpers/common';\nimport type { IProvider } from '@venizia/ignis-inversion';\nimport type { Context } from 'hono';\nimport type { ErrorHandler, HTTPResponseError } from 'hono/types';\nimport { REQUEST_ID_KEY } from '../common';\nimport { DatabaseErrorHandler } from './database.handler';\nimport {\n ApplicationErrorTypes,\n DATABASE_RETRYABLE_ERROR_CODE,\n DATABASE_RETRYABLE_ERROR_MESSAGE,\n} from './definition';\nimport type { IResolvedApplicationError, TApplicationErrorType } from './common';\nimport { ZodErrorHandler } from './zod.handler';\n\nconst DEFAULT_INTERNAL_ERROR_MESSAGE = 'Internal Server Error';\n\n/** An intentional error's throw site is still worth naming; its caller chain is framework plumbing, so it gets a smaller budget than an unexpected one. */\nconst DEFAULT_INTENTIONAL_STACK_FRAMES = 5;\nconst DEFAULT_UNEXPECTED_STACK_FRAMES = 10;\n\n/** How a thrown error is rendered into the log line. Must never throw - a throw inside the error handler turns a handled failure into an unhandled one. */\nexport type TErrorLogFormatter = (opts: {\n error: unknown;\n messageCode?: string;\n extra?: Record<string, unknown>;\n includeStack?: boolean;\n maxStackFrames?: number;\n}) => string;\n\ntype TThrown = Error | HTTPResponseError;\ntype TDatabaseClientError = ReturnType<typeof DatabaseErrorHandler.isDatabaseClientError>;\n\n/**\n * Renders a value into one log-safe fragment.\n *\n * Redaction is not optional here. This runs on `extra`, which is whatever a throw site chose to\n * attach - `getError({ extra: { apiKey } })` is a shape applications write - and in a Worker this\n * fragment lands in the browser console. `toJsonSafe` masks secret-shaped keys; a hand-rolled\n * `JSON.stringify` does not, and the server path has always redacted.\n *\n * The BigInt replacer stays: `toJsonSafe` leaves BigInt intact and `JSON.stringify` refuses it, so\n * without this a single BigInt would collapse the whole fragment to the marker below. Anything else\n * it refuses yields that marker rather than a throw - this is the last-resort error handler, where a\n * throw turns a handled failure into an unhandled one.\n */\nconst renderValue = (opts: { value: unknown }): string => {\n const { value } = opts;\n\n if (typeof value === 'string') {\n return value;\n }\n\n const safe = RedactUtility.toJsonSafe({ value });\n\n try {\n return JSON.stringify(safe) ?? String(value);\n } catch {\n // A replacer is 6x the cost of plain stringify and deopts every key, so it is installed only\n // once BigInt has actually thrown - the case it exists for, and the rare one.\n try {\n const rendered = JSON.stringify(safe, (_key, entry: unknown) =>\n typeof entry === 'bigint' ? entry.toString() : entry,\n );\n\n return rendered ?? String(value);\n } catch {\n // Not a swallowed failure: this marker IS the report, and it lands in the log line the caller\n // is building.\n return '[unrenderable]';\n }\n }\n};\n\n/**\n * Hono `onError`: ZodError -> 422, DB client error -> 400, retryable conflict -> 409, `getError` ->\n * its own status, else 500. Browser-pure: the two reads that need a host - the ambient environment\n * name and the error formatter - are constructor OPTIONS, not methods to subclass.\n *\n * They were hooks once, and three subclasses existed to answer them and nothing else. A class seam\n * is also unreachable from application code, so the browser example had to fake the environment with\n * a Hono middleware assigning `context.env`. `@venizia/ignis`'s `AppErrorMiddleware` now just\n * supplies `process.env.NODE_ENV` and `ErrorPrettier` as options.\n */\nexport class BaseAppErrorMiddleware extends BaseHelper implements IProvider<ErrorHandler> {\n private rootKey: TNullable<string>;\n private intentionalStackFrames: number;\n private unexpectedStackFrames: number;\n\n /**\n * How this host reads its ambient environment name, and the ONE option that says whether it has\n * one at all: absent means it does not (a browser), so an unresolved name is by design; present\n * but returning `undefined` means a host that should have one is misconfigured. Either way\n * {@link isProduction} fails closed.\n *\n * A function, not a string: `process.env.NODE_ENV` has to be read per request, since a test - and\n * a `--env-file` reload - can change it after the middleware is built.\n */\n private readonly environment?: () => string | undefined;\n\n /** Replaces {@link renderErrorForLog} - `@venizia/ignis` passes `ErrorPrettier`, which reaches `node:util` and so cannot live here. */\n private readonly formatErrorOverride?: TErrorLogFormatter;\n\n constructor(opts?: {\n logger?: ILogger;\n rootKey?: string;\n intentionalStackFrames?: number;\n unexpectedStackFrames?: number;\n environment?: () => string | undefined;\n formatError?: TErrorLogFormatter;\n }) {\n // `new.target`, not a literal: a subclass logs under its own name, so `@venizia/ignis`'s\n // `AppErrorMiddleware` keeps the scope it has always logged under.\n super({ scope: new.target.name });\n\n this.rootKey = opts?.rootKey;\n this.intentionalStackFrames = opts?.intentionalStackFrames ?? DEFAULT_INTENTIONAL_STACK_FRAMES;\n this.unexpectedStackFrames = opts?.unexpectedStackFrames ?? DEFAULT_UNEXPECTED_STACK_FRAMES;\n this.environment = opts?.environment;\n this.formatErrorOverride = opts?.formatError;\n\n if (opts?.logger) {\n this.logger = opts.logger;\n }\n }\n\n /** Renders a thrown error for the log, through the `formatError` option when one was given. */\n protected formatError(opts: {\n error: unknown;\n messageCode?: string;\n extra?: Record<string, unknown>;\n includeStack?: boolean;\n maxStackFrames?: number;\n }): string {\n return (this.formatErrorOverride ?? ((o) => this.renderErrorForLog(o)))(opts);\n }\n\n /**\n * The default log rendering: pure and deliberately small, so the whole middleware stays\n * browser-pure.\n *\n * Must never throw, cycles included: a throw inside the error handler turns a handled failure\n * into an unhandled one.\n */\n private renderErrorForLog(opts: {\n error: unknown;\n messageCode?: string;\n extra?: Record<string, unknown>;\n includeStack?: boolean;\n maxStackFrames?: number;\n }): string {\n const { error, messageCode, extra, includeStack = true, maxStackFrames } = opts;\n const thrown = error as Partial<Error> | null | undefined;\n const lines: Array<string> = [];\n\n if (typeof thrown?.name === 'string') {\n lines.push(`name: ${thrown.name}`);\n }\n\n lines.push(\n `message: ${typeof thrown?.message === 'string' ? thrown.message : renderValue({ value: error })}`,\n );\n\n if (messageCode) {\n lines.push(`code: ${messageCode}`);\n }\n\n if (extra && Object.keys(extra).length > 0) {\n lines.push(`extra: ${renderValue({ value: extra })}`);\n }\n\n if (includeStack && typeof thrown?.stack === 'string') {\n const frames = thrown.stack.split('\\n').filter((line) => line.trimStart().startsWith('at '));\n const capped = maxStackFrames === undefined ? frames : frames.slice(0, maxStackFrames);\n\n if (capped.length > 0) {\n lines.push(`stack:\\n${capped.join('\\n')}`);\n }\n }\n\n return lines.map((line) => `- ${line}`).join('\\n');\n }\n\n private withRootKey(payload: object) {\n return this.rootKey ? { [this.rootKey]: payload } : payload;\n }\n\n /** Fail-closed: an unset or unrecognized env is production. */\n private isProduction(opts: { context: Context; error: TThrown; requestId: string }): boolean {\n const { context, error, requestId } = opts;\n const env = [context.env?.NODE_ENV, this.environment?.()].find(Boolean);\n\n if (!env) {\n // Only a host that HAS an ambient environment can be misconfigured about it. In a browser the\n // absence is by design, and shouting it at error level on every request buries the error the\n // reader is actually looking at. Both paths still sanitize.\n if (this.environment) {\n this.logger.error(\n '[%s] INVALID ENV IDENTIFIER | env: %s | path: %s | method: %s | url: %s\\n%s',\n requestId,\n env,\n context.req.path,\n context.req.method,\n context.req.url,\n this.formatError({ error }),\n );\n } else {\n this.logger.debug(\n '[%s] No ambient environment - sanitizing as production | path: %s | set NODE_ENV on the Hono env binding to opt out',\n requestId,\n context.req.path,\n );\n }\n\n return true;\n }\n\n return !EnvironmentNames.DEVELOPMENT_ENVS.has(env.toLowerCase());\n }\n\n private classify(opts: { error: TThrown; dbError: TDatabaseClientError }): TApplicationErrorType {\n const { error, dbError } = opts;\n\n if (dbError.isClientError) {\n return ApplicationErrorTypes.DATABASE_CLIENT;\n }\n\n if (DatabaseErrorHandler.isRetryableDatabaseError({ error })) {\n return ApplicationErrorTypes.DATABASE_RETRYABLE;\n }\n\n if ('statusCode' in error || this.readClientErrorStatus({ error }) !== undefined) {\n return ApplicationErrorTypes.INTENTIONAL;\n }\n\n return ApplicationErrorTypes.UNEXPECTED;\n }\n\n /** Hono's `HTTPException` carries `status`, not `statusCode`. Only a 4xx is the caller's fault; a 5xx stays unexpected, so its message is sanitized. */\n private readClientErrorStatus(opts: { error: TThrown }): number | undefined {\n const { error } = opts;\n\n if (!('getResponse' in error) || !('status' in error) || typeof error.status !== 'number') {\n return undefined;\n }\n\n const isClientError =\n error.status >= HTTP.ResultCodes.RS_4.BadRequest &&\n error.status < HTTP.ResultCodes.RS_5.InternalServerError;\n\n return isClientError ? error.status : undefined;\n }\n\n /** `getError` sets `statusCode`, and it wins when a foreign error carries both. Neither usable is a 500. */\n private readIntentionalStatus(opts: { error: TThrown }): number {\n const { error } = opts;\n\n if ('statusCode' in error && typeof error.statusCode === 'number') {\n return error.statusCode;\n }\n\n return this.readClientErrorStatus({ error }) ?? HTTP.ResultCodes.RS_5.InternalServerError;\n }\n\n /** An ApplicationError's `normalized` is authoritative - a `transform` may have reworded `text`. */\n private build(opts: {\n error: TThrown;\n statusCode: number;\n message: string;\n type: TApplicationErrorType;\n messageCode?: string;\n }): IResolvedApplicationError {\n const { error, statusCode, message, type, messageCode } = opts;\n\n // Fallback for a FOREIGN error that sets its own code; an ApplicationError reports via `normalized`.\n const code =\n messageCode ??\n MessageCode.resolve('messageCode' in error ? (error.messageCode as string) : undefined);\n\n const normalized =\n 'normalized' in error\n ? (error.normalized as IResolvedApplicationError['normalized'])\n : { text: message, code, args: {} };\n\n return { statusCode, message, normalized, type };\n }\n\n private resolve(opts: { error: TThrown; isProduction: boolean }): IResolvedApplicationError {\n const { error, isProduction } = opts;\n const dbError = DatabaseErrorHandler.isDatabaseClientError({ error, isProduction });\n const type = this.classify({ error, dbError });\n\n switch (type) {\n case ApplicationErrorTypes.DATABASE_CLIENT: {\n return this.build({\n error,\n type,\n statusCode: HTTP.ResultCodes.RS_4.BadRequest,\n // The fallback is unreachable today; it keeps the driver's raw text from ever surfacing.\n message: dbError.message ?? DEFAULT_INTERNAL_ERROR_MESSAGE,\n });\n }\n\n case ApplicationErrorTypes.DATABASE_RETRYABLE: {\n return this.build({\n error,\n type,\n statusCode: HTTP.ResultCodes.RS_4.Conflict,\n message: DATABASE_RETRYABLE_ERROR_MESSAGE,\n messageCode: DATABASE_RETRYABLE_ERROR_CODE,\n });\n }\n\n case ApplicationErrorTypes.INTENTIONAL: {\n return this.build({\n error,\n type,\n statusCode: this.readIntentionalStatus({ error }),\n message: error.message,\n });\n }\n\n default: {\n return this.build({\n error,\n type: ApplicationErrorTypes.UNEXPECTED,\n statusCode: HTTP.ResultCodes.RS_5.InternalServerError,\n // Never leak a raw message - it may carry SQL, schema names or connection details.\n message: isProduction ? DEFAULT_INTERNAL_ERROR_MESSAGE : error.message,\n });\n }\n }\n }\n\n /** A throw site may set `logLevel` via `getError`; anything unset or malformed logs at `error`. */\n private resolveLogLevel(opts: { error: TThrown }): TLogLevel {\n const candidate = (opts.error as { logLevel?: unknown }).logLevel;\n\n if (typeof candidate === 'string' && LogLevels.isValid(candidate)) {\n return candidate as TLogLevel;\n }\n\n return LogLevels.ERROR;\n }\n\n /** The one place a thrown error reaches the log - called once the status is known, so it carries it. */\n private logError(opts: {\n error: TThrown;\n context: Context;\n requestId: string;\n statusCode: number;\n messageCode: string;\n type?: TApplicationErrorType;\n }) {\n const { error, context, requestId, statusCode, messageCode, type } = opts;\n\n this.logger.log(\n this.resolveLogLevel({ error }),\n '[%s] REQUEST ERROR | %s | %s %s\\n%s',\n requestId,\n statusCode,\n context.req.method,\n context.req.url,\n this.formatError({\n error,\n // The default code means \"no code\" - logging it on every error would be a noise line.\n messageCode: messageCode === MessageCode.DEFAULT ? undefined : messageCode,\n extra: 'extra' in error ? (error.extra as Record<string, unknown>) : undefined,\n includeStack: true,\n // An intentional error still needs its throw site; it just does not need the caller chain behind it.\n maxStackFrames:\n type === ApplicationErrorTypes.UNEXPECTED\n ? this.unexpectedStackFrames\n : this.intentionalStackFrames,\n }),\n );\n }\n\n /** Only an intentional error's message is a catalog template; every other branch writes its own text, so it passes through as is. */\n private renderMessage(opts: {\n resolved: IResolvedApplicationError;\n isProduction: boolean;\n requestId: string;\n }): string {\n const { resolved, isProduction, requestId } = opts;\n\n if (resolved.type !== ApplicationErrorTypes.INTENTIONAL) {\n return resolved.message;\n }\n\n const { text, missing } = MessageTemplate.render({\n text: resolved.message,\n args: resolved.normalized.args,\n });\n\n // Production stays silent and renders what it can; anywhere else a missing arg is a throw site to fix.\n if (missing.length > 0 && !isProduction) {\n this.logger.warn(\n '[%s] MESSAGE PLACEHOLDER WITHOUT ARG | code: %s | keys: %s',\n requestId,\n resolved.normalized.code,\n missing.join(', '),\n );\n }\n\n return text;\n }\n\n value(): ErrorHandler {\n return async (error, context) => {\n const requestId = context.get(REQUEST_ID_KEY);\n const isProduction = this.isProduction({ context, error, requestId });\n\n if (error.name === 'ZodError') {\n const rs = ZodErrorHandler.formatZodError({\n isProduction,\n requestId,\n url: context.req.url,\n path: context.req.path,\n error,\n });\n\n this.logError({\n error,\n context,\n requestId,\n statusCode: rs.statusCode,\n messageCode: rs.response.normalized.code,\n });\n\n return context.json(\n this.withRootKey(rs.response),\n rs.statusCode as Parameters<typeof context.json>[1],\n );\n }\n\n const resolved = this.resolve({ error, isProduction });\n const { statusCode, normalized, type } = resolved;\n\n this.logError({ error, context, requestId, statusCode, messageCode: normalized.code, type });\n\n const rs = {\n message: this.renderMessage({ resolved, isProduction, requestId }),\n statusCode,\n normalized,\n requestId,\n extra: 'extra' in error ? error?.extra : undefined,\n details: {\n url: context.req.url,\n path: context.req.path,\n stack: !isProduction ? error.stack : undefined,\n cause: !isProduction ? error.cause : undefined,\n },\n };\n\n return context.json(this.withRootKey(rs), statusCode as Parameters<typeof context.json>[1]);\n };\n }\n}\n"]}
@@ -1,13 +1,15 @@
1
- /** True for a database error caused by the request (SQLSTATE class 22/23/44) -> HTTP 400; in production the detail/table/constraint context is suppressed so no row values or schema internals leak. */
2
- export declare const isDatabaseClientError: (opts: {
3
- error: Error;
4
- isProduction: boolean;
5
- }) => {
6
- isClientError: boolean;
7
- message?: string;
8
- };
9
- /** True for a transient, retryable transaction conflict (serialization failure / deadlock - SQLSTATE 40001 / 40P01) -> HTTP 409: the client can retry the same request. */
10
- export declare const isRetryableDatabaseError: (opts: {
11
- error: Error;
12
- }) => boolean;
1
+ export declare class DatabaseErrorHandler {
2
+ /** True for a database error caused by the request (SQLSTATE class 22/23/44) -> HTTP 400; in production the detail/table/constraint context is suppressed so no row values or schema internals leak. */
3
+ static isDatabaseClientError(opts: {
4
+ error: Error;
5
+ isProduction: boolean;
6
+ }): {
7
+ isClientError: boolean;
8
+ message?: string;
9
+ };
10
+ /** True for a transient, retryable transaction conflict (serialization failure / deadlock - SQLSTATE 40001 / 40P01) -> HTTP 409: the client can retry the same request. */
11
+ static isRetryableDatabaseError(opts: {
12
+ error: Error;
13
+ }): boolean;
14
+ }
13
15
  //# sourceMappingURL=database.handler.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"database.handler.d.ts","sourceRoot":"","sources":["../../../../../src/base/middlewares/app-error/database.handler.ts"],"names":[],"mappings":"AAQA,wMAAwM;AACxM,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;CAqC7C,CAAC;AAEF,2KAA2K;AAC3K,eAAO,MAAM,wBAAwB,GAAI,MAAM;IAAE,KAAK,EAAE,KAAK,CAAA;CAAE,KAAG,OAIjE,CAAC"}
1
+ {"version":3,"file":"database.handler.d.ts","sourceRoot":"","sources":["../../../../../src/base/middlewares/app-error/database.handler.ts"],"names":[],"mappings":"AAQA,qBAAa,oBAAoB;IAC/B,wMAAwM;IACxM,MAAM,CAAC,qBAAqB,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,KAAK,CAAC;QAAC,YAAY,EAAE,OAAO,CAAA;KAAE,GAAG;QAC3E,aAAa,EAAE,OAAO,CAAC;QACvB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB;IAuCD,2KAA2K;IAC3K,MAAM,CAAC,wBAAwB,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,KAAK,CAAA;KAAE,GAAG,OAAO;CAKjE"}
@@ -1,39 +1,41 @@
1
1
  import { DATABASE_CLIENT_ERROR_FALLBACK_MESSAGE, DATABASE_CLIENT_ERROR_MESSAGES, POSTGRES_CLIENT_ERROR_CLASSES, POSTGRES_RETRYABLE_ERROR_CODES, } from './definition.js';
2
- /** True for a database error caused by the request (SQLSTATE class 22/23/44) -> HTTP 400; in production the detail/table/constraint context is suppressed so no row values or schema internals leak. */
3
- export const isDatabaseClientError = (opts) => {
4
- const { error, isProduction } = opts;
5
- const dbError = error;
6
- const cause = dbError.cause;
7
- const code = [dbError.code, cause?.code].find(Boolean);
8
- // Only request-caused SQLSTATE classes are client errors; a missing or non-string code (e.g. a gRPC numeric one) is non-client and must never crash this last-resort handler.
9
- if (typeof code !== 'string' || !POSTGRES_CLIENT_ERROR_CLASSES.includes(code.slice(0, 2))) {
10
- return { isClientError: false };
2
+ export class DatabaseErrorHandler {
3
+ /** True for a database error caused by the request (SQLSTATE class 22/23/44) -> HTTP 400; in production the detail/table/constraint context is suppressed so no row values or schema internals leak. */
4
+ static isDatabaseClientError(opts) {
5
+ const { error, isProduction } = opts;
6
+ const dbError = error;
7
+ const cause = dbError.cause;
8
+ const code = [dbError.code, cause?.code].find(Boolean);
9
+ // Only request-caused SQLSTATE classes are client errors; a missing or non-string code (e.g. a gRPC numeric one) is non-client and must never crash this last-resort handler.
10
+ if (typeof code !== 'string' || !POSTGRES_CLIENT_ERROR_CLASSES.includes(code.slice(0, 2))) {
11
+ return { isClientError: false };
12
+ }
13
+ const baseMessage = DATABASE_CLIENT_ERROR_MESSAGES[code] ?? DATABASE_CLIENT_ERROR_FALLBACK_MESSAGE;
14
+ // In production expose ONLY the generic base message: `detail` can echo row values and `table`/`constraint` reveal schema internals.
15
+ if (isProduction) {
16
+ return { isClientError: true, message: baseMessage };
17
+ }
18
+ // Non-production: append driver-provided context to aid debugging.
19
+ const lines = [baseMessage];
20
+ if (cause?.detail) {
21
+ lines.push(`Detail: ${cause.detail}`);
22
+ }
23
+ if (cause?.table) {
24
+ lines.push(`Table: ${cause.table}`);
25
+ }
26
+ if (cause?.constraint) {
27
+ lines.push(`Constraint: ${cause.constraint}`);
28
+ }
29
+ return {
30
+ isClientError: true,
31
+ message: lines.join('\n'),
32
+ };
11
33
  }
12
- const baseMessage = DATABASE_CLIENT_ERROR_MESSAGES[code] ?? DATABASE_CLIENT_ERROR_FALLBACK_MESSAGE;
13
- // In production expose ONLY the generic base message: `detail` can echo row values and `table`/`constraint` reveal schema internals.
14
- if (isProduction) {
15
- return { isClientError: true, message: baseMessage };
34
+ /** True for a transient, retryable transaction conflict (serialization failure / deadlock - SQLSTATE 40001 / 40P01) -> HTTP 409: the client can retry the same request. */
35
+ static isRetryableDatabaseError(opts) {
36
+ const dbError = opts.error;
37
+ const code = [dbError.code, dbError.cause?.code].find(Boolean);
38
+ return typeof code === 'string' && POSTGRES_RETRYABLE_ERROR_CODES.includes(code);
16
39
  }
17
- // Non-production: append driver-provided context to aid debugging.
18
- const lines = [baseMessage];
19
- if (cause?.detail) {
20
- lines.push(`Detail: ${cause.detail}`);
21
- }
22
- if (cause?.table) {
23
- lines.push(`Table: ${cause.table}`);
24
- }
25
- if (cause?.constraint) {
26
- lines.push(`Constraint: ${cause.constraint}`);
27
- }
28
- return {
29
- isClientError: true,
30
- message: lines.join('\n'),
31
- };
32
- };
33
- /** True for a transient, retryable transaction conflict (serialization failure / deadlock - SQLSTATE 40001 / 40P01) -> HTTP 409: the client can retry the same request. */
34
- export const isRetryableDatabaseError = (opts) => {
35
- const dbError = opts.error;
36
- const code = [dbError.code, dbError.cause?.code].find(Boolean);
37
- return typeof code === 'string' && POSTGRES_RETRYABLE_ERROR_CODES.includes(code);
38
- };
40
+ }
39
41
  //# sourceMappingURL=database.handler.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"database.handler.js","sourceRoot":"","sources":["../../../../../src/base/middlewares/app-error/database.handler.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sCAAsC,EACtC,8BAA8B,EAC9B,6BAA6B,EAC7B,8BAA8B,GAC/B,MAAM,cAAc,CAAC;AAGtB,wMAAwM;AACxM,MAAM,CAAC,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,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAEvD,8KAA8K;IAC9K,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,6BAA6B,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,8BAA8B,CAAC,IAAI,CAAC,IAAI,sCAAsC,CAAC;IAEjF,qIAAqI;IACrI,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;AAEF,2KAA2K;AAC3K,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,IAAsB,EAAW,EAAE;IAC1E,MAAM,OAAO,GAAG,IAAI,CAAC,KAAuB,CAAC;IAC7C,MAAM,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC/D,OAAO,OAAO,IAAI,KAAK,QAAQ,IAAI,8BAA8B,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACnF,CAAC,CAAC","sourcesContent":["import {\n DATABASE_CLIENT_ERROR_FALLBACK_MESSAGE,\n DATABASE_CLIENT_ERROR_MESSAGES,\n POSTGRES_CLIENT_ERROR_CLASSES,\n POSTGRES_RETRYABLE_ERROR_CODES,\n} from './definition';\nimport type { IDatabaseError } from './common';\n\n/** True for a database error caused by the request (SQLSTATE class 22/23/44) -> HTTP 400; in production the detail/table/constraint context is suppressed so no row values or schema internals leak. */\nexport const isDatabaseClientError = (opts: {\n error: Error;\n isProduction: boolean;\n}): { isClientError: boolean; message?: string } => {\n const { error, isProduction } = opts;\n const dbError = error as IDatabaseError;\n const cause = dbError.cause;\n const code = [dbError.code, cause?.code].find(Boolean);\n\n // Only request-caused SQLSTATE classes are client errors; a missing or non-string code (e.g. a gRPC numeric one) is non-client and must never crash this last-resort handler.\n if (typeof code !== 'string' || !POSTGRES_CLIENT_ERROR_CLASSES.includes(code.slice(0, 2))) {\n return { isClientError: false };\n }\n\n const baseMessage =\n DATABASE_CLIENT_ERROR_MESSAGES[code] ?? DATABASE_CLIENT_ERROR_FALLBACK_MESSAGE;\n\n // In production expose ONLY the generic base message: `detail` can echo row values and `table`/`constraint` reveal schema internals.\n if (isProduction) {\n return { isClientError: true, message: baseMessage };\n }\n\n // Non-production: append driver-provided context to aid debugging.\n const lines = [baseMessage];\n if (cause?.detail) {\n lines.push(`Detail: ${cause.detail}`);\n }\n\n if (cause?.table) {\n lines.push(`Table: ${cause.table}`);\n }\n\n if (cause?.constraint) {\n lines.push(`Constraint: ${cause.constraint}`);\n }\n\n return {\n isClientError: true,\n message: lines.join('\\n'),\n };\n};\n\n/** True for a transient, retryable transaction conflict (serialization failure / deadlock - SQLSTATE 40001 / 40P01) -> HTTP 409: the client can retry the same request. */\nexport const isRetryableDatabaseError = (opts: { error: Error }): boolean => {\n const dbError = opts.error as IDatabaseError;\n const code = [dbError.code, dbError.cause?.code].find(Boolean);\n return typeof code === 'string' && POSTGRES_RETRYABLE_ERROR_CODES.includes(code);\n};\n"]}
1
+ {"version":3,"file":"database.handler.js","sourceRoot":"","sources":["../../../../../src/base/middlewares/app-error/database.handler.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sCAAsC,EACtC,8BAA8B,EAC9B,6BAA6B,EAC7B,8BAA8B,GAC/B,MAAM,cAAc,CAAC;AAGtB,MAAM,OAAO,oBAAoB;IAC/B,wMAAwM;IACxM,MAAM,CAAC,qBAAqB,CAAC,IAA6C;QAIxE,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC;QACrC,MAAM,OAAO,GAAG,KAAuB,CAAC;QACxC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC5B,MAAM,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAEvD,8KAA8K;QAC9K,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,6BAA6B,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC1F,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC;QAClC,CAAC;QAED,MAAM,WAAW,GACf,8BAA8B,CAAC,IAAI,CAAC,IAAI,sCAAsC,CAAC;QAEjF,qIAAqI;QACrI,IAAI,YAAY,EAAE,CAAC;YACjB,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC;QACvD,CAAC;QAED,mEAAmE;QACnE,MAAM,KAAK,GAAG,CAAC,WAAW,CAAC,CAAC;QAC5B,IAAI,KAAK,EAAE,MAAM,EAAE,CAAC;YAClB,KAAK,CAAC,IAAI,CAAC,WAAW,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;QACxC,CAAC;QAED,IAAI,KAAK,EAAE,KAAK,EAAE,CAAC;YACjB,KAAK,CAAC,IAAI,CAAC,UAAU,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;QACtC,CAAC;QAED,IAAI,KAAK,EAAE,UAAU,EAAE,CAAC;YACtB,KAAK,CAAC,IAAI,CAAC,eAAe,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC;QAChD,CAAC;QAED,OAAO;YACL,aAAa,EAAE,IAAI;YACnB,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;SAC1B,CAAC;IACJ,CAAC;IAED,2KAA2K;IAC3K,MAAM,CAAC,wBAAwB,CAAC,IAAsB;QACpD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAuB,CAAC;QAC7C,MAAM,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC/D,OAAO,OAAO,IAAI,KAAK,QAAQ,IAAI,8BAA8B,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACnF,CAAC;CACF","sourcesContent":["import {\n DATABASE_CLIENT_ERROR_FALLBACK_MESSAGE,\n DATABASE_CLIENT_ERROR_MESSAGES,\n POSTGRES_CLIENT_ERROR_CLASSES,\n POSTGRES_RETRYABLE_ERROR_CODES,\n} from './definition';\nimport type { IDatabaseError } from './common';\n\nexport class DatabaseErrorHandler {\n /** True for a database error caused by the request (SQLSTATE class 22/23/44) -> HTTP 400; in production the detail/table/constraint context is suppressed so no row values or schema internals leak. */\n static isDatabaseClientError(opts: { error: Error; isProduction: boolean }): {\n isClientError: boolean;\n message?: string;\n } {\n const { error, isProduction } = opts;\n const dbError = error as IDatabaseError;\n const cause = dbError.cause;\n const code = [dbError.code, cause?.code].find(Boolean);\n\n // Only request-caused SQLSTATE classes are client errors; a missing or non-string code (e.g. a gRPC numeric one) is non-client and must never crash this last-resort handler.\n if (typeof code !== 'string' || !POSTGRES_CLIENT_ERROR_CLASSES.includes(code.slice(0, 2))) {\n return { isClientError: false };\n }\n\n const baseMessage =\n DATABASE_CLIENT_ERROR_MESSAGES[code] ?? DATABASE_CLIENT_ERROR_FALLBACK_MESSAGE;\n\n // In production expose ONLY the generic base message: `detail` can echo row values and `table`/`constraint` reveal schema internals.\n if (isProduction) {\n return { isClientError: true, message: baseMessage };\n }\n\n // Non-production: append driver-provided context to aid debugging.\n const lines = [baseMessage];\n if (cause?.detail) {\n lines.push(`Detail: ${cause.detail}`);\n }\n\n if (cause?.table) {\n lines.push(`Table: ${cause.table}`);\n }\n\n if (cause?.constraint) {\n lines.push(`Constraint: ${cause.constraint}`);\n }\n\n return {\n isClientError: true,\n message: lines.join('\\n'),\n };\n }\n\n /** True for a transient, retryable transaction conflict (serialization failure / deadlock - SQLSTATE 40001 / 40P01) -> HTTP 409: the client can retry the same request. */\n static isRetryableDatabaseError(opts: { error: Error }): boolean {\n const dbError = opts.error as IDatabaseError;\n const code = [dbError.code, dbError.cause?.code].find(Boolean);\n return typeof code === 'string' && POSTGRES_RETRYABLE_ERROR_CODES.includes(code);\n }\n}\n"]}
@@ -1,28 +1,33 @@
1
1
  import type { HTTPResponseError } from 'hono/types';
2
- /** Formats a ZodError into the 422 validation response. */
3
- export declare const formatZodError: (opts: {
4
- isProduction: boolean;
5
- requestId: string;
6
- url: string;
7
- path: string;
8
- error: Error | HTTPResponseError;
9
- }) => {
10
- statusCode: 422;
11
- response: {
12
- message: string;
13
- statusCode: 422;
14
- normalized: {
15
- text: string;
16
- code: string;
17
- args: {};
18
- };
2
+ export declare class ZodErrorHandler {
3
+ private static readonly DEFAULT_VALIDATION_MESSAGE;
4
+ /** Returns a schema-author-supplied code (`issue.params.code`) when it is a non-empty string. */
5
+ private static extractIssueCode;
6
+ /** Formats a ZodError into the 422 validation response. */
7
+ static formatZodError(opts: {
8
+ isProduction: boolean;
19
9
  requestId: string;
20
- details: {
21
- url: string;
22
- path: string;
23
- stack: string | undefined;
24
- cause: unknown;
10
+ url: string;
11
+ path: string;
12
+ error: Error | HTTPResponseError;
13
+ }): {
14
+ statusCode: 422;
15
+ response: {
16
+ message: string;
17
+ statusCode: 422;
18
+ normalized: {
19
+ text: string;
20
+ code: string;
21
+ args: {};
22
+ };
23
+ requestId: string;
24
+ details: {
25
+ url: string;
26
+ path: string;
27
+ stack: string | undefined;
28
+ cause: unknown;
29
+ };
25
30
  };
26
31
  };
27
- };
32
+ }
28
33
  //# sourceMappingURL=zod.handler.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"zod.handler.d.ts","sourceRoot":"","sources":["../../../../../src/base/middlewares/app-error/zod.handler.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAgBpD,2DAA2D;AAC3D,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;;;;;;;;;;;;;;;;;;CAmDA,CAAC"}
1
+ {"version":3,"file":"zod.handler.d.ts","sourceRoot":"","sources":["../../../../../src/base/middlewares/app-error/zod.handler.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAGpD,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,0BAA0B,CAAqB;IAEvE,iGAAiG;IACjG,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAU/B,2DAA2D;IAC3D,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE;QAC1B,YAAY,EAAE,OAAO,CAAC;QACtB,SAAS,EAAE,MAAM,CAAC;QAClB,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,KAAK,GAAG,iBAAiB,CAAC;KAClC;;;;;;;;;;;;;;;;;;;CAqDF"}