90dc-core 1.16.14 → 1.16.16

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.
package/dist/index.d.ts CHANGED
@@ -15,7 +15,7 @@ export { NotificationClient } from "./lib/utils/NotificationClient.js";
15
15
  export { Log } from "./lib/utils/Logger.js";
16
16
  export { SecretManager } from "./lib/utils/SecretManager.js";
17
17
  export { initializeSentry, isSentryEnabled, scrubObject, captureRequestBody, extractUserContext, buildRequestContext, buildResponseContext, reportErrorToSentry, reportMessageToSentry, type ErrorReportOptions, type SeverityLevel, } from "./lib/utils/SentryUtil.js";
18
- export { createMockContext, createMockUser, createAuthenticatedContext, mockDatabase, setupDatabaseMocks, flushPromises, assertions, executeRoute, createMockFile, createMockFiles, createMockTransaction, setupTimeMocks, MockValidationError, MockNotFoundError, MockDatabaseError, createTypedMock, spyOnPrototype, TEST_CONSTANTS, type BaseContext, type AuthenticatedContext, type RouterContext, type RouterMiddleware, type RouterLayer, type RouterLike, type SequelizeModelMethods, type MockFile, type MockTransaction, type DatabaseMocks, type TimeMocks, } from "./lib/testing/testHelpers.js";
18
+ export { createMockContext, createMockUser, createAuthenticatedContext, mockDatabase, flushPromises, assertions, executeRoute, type BaseContext, type AuthenticatedContext, type RouterContext, type RouterMiddleware, type RouterLayer, type RouterLike, type SequelizeModelMethods, } from "./lib/testing/testHelpers.js";
19
19
  export { ConfigValidator, BaseConfigSchema, CommonSchemas, createConfig, ConfigurationError, type BaseConfig } from "./lib/config/ConfigValidator.js";
20
20
  export { AppError, ValidationError, AuthenticationError, ForbiddenError, NotFoundError, ConflictError, UnprocessableEntityError, RateLimitError, InternalServerError, ServiceUnavailableError, DatabaseError, ExternalAPIError, isAppError, isOperationalError, toAppError } from "./lib/Errors/AppError.js";
21
21
  export { ErrorMiddleware, } from "./lib/middlewares/ErrorMiddleware.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,mCAAmC,CAAC;AAClD,cAAc,oCAAoC,CAAC;AACnD,cAAc,mCAAmC,CAAC;AAClD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,wCAAwC,CAAC;AAGvD,cAAc,yBAAyB,CAAA;AAGvC,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAA;AAC1D,OAAO,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAA;AAChF,OAAO,EAAE,8BAA8B,EAAE,MAAM,iDAAiD,CAAA;AAChG,YAAY,EACV,wBAAwB,EACxB,yBAAyB,EACzB,aAAa,GACd,MAAM,8BAA8B,CAAA;AACrC,YAAY,EAAE,mBAAmB,EAAE,MAAM,yCAAyC,CAAA;AAGlF,OAAO,EAAC,kBAAkB,EAAC,MAAM,mCAAmC,CAAA;AACpE,OAAO,EAAC,iBAAiB,EAAC,MAAM,kCAAkC,CAAA;AAClE,OAAO,EAAC,kBAAkB,EAAC,MAAM,mCAAmC,CAAA;AACpE,OAAO,EAAC,GAAG,EAAC,MAAM,uBAAuB,CAAA;AACzC,OAAO,EAAC,aAAa,EAAC,MAAM,8BAA8B,CAAA;AAC1D,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,WAAW,EACX,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACnB,qBAAqB,EACrB,KAAK,kBAAkB,EACvB,KAAK,aAAa,GACnB,MAAM,2BAA2B,CAAA;AAGlC,OAAO,EAEL,iBAAiB,EACjB,cAAc,EACd,0BAA0B,EAE1B,YAAY,EACZ,kBAAkB,EAElB,aAAa,EAEb,UAAU,EAEV,YAAY,EAEZ,cAAc,EACd,eAAe,EACf,qBAAqB,EAErB,cAAc,EAEd,mBAAmB,EACnB,iBAAiB,EACjB,iBAAiB,EAEjB,eAAe,EACf,cAAc,EAEd,cAAc,EAEd,KAAK,WAAW,EAChB,KAAK,oBAAoB,EACzB,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,qBAAqB,EAC1B,KAAK,QAAQ,EACb,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,SAAS,GACf,MAAM,8BAA8B,CAAA;AAGrC,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,YAAY,EACZ,kBAAkB,EAClB,KAAK,UAAU,EAChB,MAAM,iCAAiC,CAAA;AAGxC,OAAO,EACL,QAAQ,EACR,eAAe,EACf,mBAAmB,EACnB,cAAc,EACd,aAAa,EACb,aAAa,EACb,wBAAwB,EACxB,cAAc,EACd,mBAAmB,EACnB,uBAAuB,EACvB,aAAa,EACb,gBAAgB,EAChB,UAAU,EACV,kBAAkB,EAClB,UAAU,EACX,MAAM,0BAA0B,CAAA;AAGjC,OAAO,EACL,eAAe,GAChB,MAAM,sCAAsC,CAAA;AAC7C,OAAO,EAAE,QAAQ,EAAE,KAAK,gBAAgB,EAAE,MAAM,2CAA2C,CAAC;AAG5F,OAAO,EAAE,cAAc,EAAE,KAAK,WAAW,EAAE,MAAM,qCAAqC,CAAC;AAGvF,OAAO,EAAC,WAAW,EAAC,MAAM,wBAAwB,CAAA;AAClD,OAAO,EAAC,cAAc,EAAE,KAAK,cAAc,EAAC,MAAM,2BAA2B,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,mCAAmC,CAAC;AAClD,cAAc,oCAAoC,CAAC;AACnD,cAAc,mCAAmC,CAAC;AAClD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,wCAAwC,CAAC;AAGvD,cAAc,yBAAyB,CAAA;AAGvC,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAA;AAC1D,OAAO,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAA;AAChF,OAAO,EAAE,8BAA8B,EAAE,MAAM,iDAAiD,CAAA;AAChG,YAAY,EACV,wBAAwB,EACxB,yBAAyB,EACzB,aAAa,GACd,MAAM,8BAA8B,CAAA;AACrC,YAAY,EAAE,mBAAmB,EAAE,MAAM,yCAAyC,CAAA;AAGlF,OAAO,EAAC,kBAAkB,EAAC,MAAM,mCAAmC,CAAA;AACpE,OAAO,EAAC,iBAAiB,EAAC,MAAM,kCAAkC,CAAA;AAClE,OAAO,EAAC,kBAAkB,EAAC,MAAM,mCAAmC,CAAA;AACpE,OAAO,EAAC,GAAG,EAAC,MAAM,uBAAuB,CAAA;AACzC,OAAO,EAAC,aAAa,EAAC,MAAM,8BAA8B,CAAA;AAC1D,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,WAAW,EACX,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACnB,qBAAqB,EACrB,KAAK,kBAAkB,EACvB,KAAK,aAAa,GACnB,MAAM,2BAA2B,CAAA;AAGlC,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,0BAA0B,EAC1B,YAAY,EACZ,aAAa,EACb,UAAU,EACV,YAAY,EACZ,KAAK,WAAW,EAChB,KAAK,oBAAoB,EACzB,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,qBAAqB,GAC3B,MAAM,8BAA8B,CAAA;AAGrC,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,YAAY,EACZ,kBAAkB,EAClB,KAAK,UAAU,EAChB,MAAM,iCAAiC,CAAA;AAGxC,OAAO,EACL,QAAQ,EACR,eAAe,EACf,mBAAmB,EACnB,cAAc,EACd,aAAa,EACb,aAAa,EACb,wBAAwB,EACxB,cAAc,EACd,mBAAmB,EACnB,uBAAuB,EACvB,aAAa,EACb,gBAAgB,EAChB,UAAU,EACV,kBAAkB,EAClB,UAAU,EACX,MAAM,0BAA0B,CAAA;AAGjC,OAAO,EACL,eAAe,GAChB,MAAM,sCAAsC,CAAA;AAC7C,OAAO,EAAE,QAAQ,EAAE,KAAK,gBAAgB,EAAE,MAAM,2CAA2C,CAAC;AAG5F,OAAO,EAAE,cAAc,EAAE,KAAK,WAAW,EAAE,MAAM,qCAAqC,CAAC;AAGvF,OAAO,EAAC,WAAW,EAAC,MAAM,wBAAwB,CAAA;AAClD,OAAO,EAAC,cAAc,EAAE,KAAK,cAAc,EAAC,MAAM,2BAA2B,CAAA"}
package/dist/index.js CHANGED
@@ -18,17 +18,7 @@ export { Log } from "./lib/utils/Logger.js";
18
18
  export { SecretManager } from "./lib/utils/SecretManager.js";
19
19
  export { initializeSentry, isSentryEnabled, scrubObject, captureRequestBody, extractUserContext, buildRequestContext, buildResponseContext, reportErrorToSentry, reportMessageToSentry } from "./lib/utils/SentryUtil.js";
20
20
  //Testing Utilities
21
- export { // Context helpers
22
- createMockContext, createMockUser, createAuthenticatedContext, // Database mocks
23
- mockDatabase, setupDatabaseMocks, // Async helpers
24
- flushPromises, // Assertions
25
- assertions, // Route execution
26
- executeRoute, // Factory helpers
27
- createMockFile, createMockFiles, createMockTransaction, // Time mocking
28
- setupTimeMocks, // Mock errors
29
- MockValidationError, MockNotFoundError, MockDatabaseError, // Typed mocking helpers
30
- createTypedMock, spyOnPrototype, // Constants
31
- TEST_CONSTANTS } from "./lib/testing/testHelpers.js";
21
+ export { createMockContext, createMockUser, createAuthenticatedContext, mockDatabase, flushPromises, assertions, executeRoute } from "./lib/testing/testHelpers.js";
32
22
  //Config
33
23
  export { ConfigValidator, BaseConfigSchema, CommonSchemas, createConfig, ConfigurationError } from "./lib/config/ConfigValidator.js";
34
24
  //Errors
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["//Interfaces\nexport * from \"./lib/models/ProgramInterfaces.js\";\nexport * from \"./lib/models/ExerciseInterfaces.js\";\nexport * from \"./lib/models/WorkoutInterfaces.js\";\nexport * from \"./lib/models/UserInterfaces.js\";\nexport * from \"./lib/models/NotificationInterfaces.js\";\n\n//DB Models - Export all models and model arrays\nexport * from \"./lib/dbmodels/index.js\"\n\n//Clients\nexport { EmailClient } from \"./lib/clients/EmailClient.js\"\nexport { PushNotificationClient } from \"./lib/clients/PushNotificationClient.js\"\nexport { FirebasePushNotificationClient } from \"./lib/clients/FirebasePushNotificationClient.js\"\nexport type {\n SendTemplateEmailRequest,\n BatchTemplateEmailRequest,\n EmailResponse,\n} from \"./lib/clients/EmailClient.js\"\nexport type { NotificationPayload } from \"./lib/clients/PushNotificationClient.js\"\n\n//Utils\nexport {AuthenticationUtil} from \"./lib/utils/AuthenticationUtil.js\"\nexport {NotificationsUtil} from \"./lib/utils/NotificationsUtil.js\"\nexport {NotificationClient} from \"./lib/utils/NotificationClient.js\"\nexport {Log} from \"./lib/utils/Logger.js\"\nexport {SecretManager} from \"./lib/utils/SecretManager.js\"\nexport {\n initializeSentry,\n isSentryEnabled,\n scrubObject,\n captureRequestBody,\n extractUserContext,\n buildRequestContext,\n buildResponseContext,\n reportErrorToSentry,\n reportMessageToSentry,\n type ErrorReportOptions,\n type SeverityLevel,\n} from \"./lib/utils/SentryUtil.js\"\n\n//Testing Utilities\nexport {\n // Context helpers\n createMockContext,\n createMockUser,\n createAuthenticatedContext,\n // Database mocks\n mockDatabase,\n setupDatabaseMocks,\n // Async helpers\n flushPromises,\n // Assertions\n assertions,\n // Route execution\n executeRoute,\n // Factory helpers\n createMockFile,\n createMockFiles,\n createMockTransaction,\n // Time mocking\n setupTimeMocks,\n // Mock errors\n MockValidationError,\n MockNotFoundError,\n MockDatabaseError,\n // Typed mocking helpers\n createTypedMock,\n spyOnPrototype,\n // Constants\n TEST_CONSTANTS,\n // Types\n type BaseContext,\n type AuthenticatedContext,\n type RouterContext,\n type RouterMiddleware,\n type RouterLayer,\n type RouterLike,\n type SequelizeModelMethods,\n type MockFile,\n type MockTransaction,\n type DatabaseMocks,\n type TimeMocks,\n} from \"./lib/testing/testHelpers.js\"\n\n//Config\nexport {\n ConfigValidator,\n BaseConfigSchema,\n CommonSchemas,\n createConfig,\n ConfigurationError,\n type BaseConfig\n} from \"./lib/config/ConfigValidator.js\"\n\n//Errors\nexport {\n AppError,\n ValidationError,\n AuthenticationError,\n ForbiddenError,\n NotFoundError,\n ConflictError,\n UnprocessableEntityError,\n RateLimitError,\n InternalServerError,\n ServiceUnavailableError,\n DatabaseError,\n ExternalAPIError,\n isAppError,\n isOperationalError,\n toAppError\n} from \"./lib/Errors/AppError.js\"\n\n//Middlewares\nexport {\n ErrorMiddleware,\n} from \"./lib/middlewares/ErrorMiddleware.js\"\nexport { validate, type ValidationConfig } from \"./lib/middlewares/ValidationMiddleware.js\";\n\n//Controllers\nexport { BaseController, type RouteConfig } from \"./lib/controllers/BaseController.js\";\n\n\nexport {RedisClient} from \"./lib/classes/Redis.js\"\nexport {DatabaseClient, type DatabaseConfig} from \"./lib/classes/Database.js\""],"names":["EmailClient","PushNotificationClient","FirebasePushNotificationClient","AuthenticationUtil","NotificationsUtil","NotificationClient","Log","SecretManager","initializeSentry","isSentryEnabled","scrubObject","captureRequestBody","extractUserContext","buildRequestContext","buildResponseContext","reportErrorToSentry","reportMessageToSentry","createMockContext","createMockUser","createAuthenticatedContext","mockDatabase","setupDatabaseMocks","flushPromises","assertions","executeRoute","createMockFile","createMockFiles","createMockTransaction","setupTimeMocks","MockValidationError","MockNotFoundError","MockDatabaseError","createTypedMock","spyOnPrototype","TEST_CONSTANTS","ConfigValidator","BaseConfigSchema","CommonSchemas","createConfig","ConfigurationError","AppError","ValidationError","AuthenticationError","ForbiddenError","NotFoundError","ConflictError","UnprocessableEntityError","RateLimitError","InternalServerError","ServiceUnavailableError","DatabaseError","ExternalAPIError","isAppError","isOperationalError","toAppError","ErrorMiddleware","validate","BaseController","RedisClient","DatabaseClient"],"mappings":"AAAA,YAAY;AACZ,cAAc,oCAAoC;AAClD,cAAc,qCAAqC;AACnD,cAAc,oCAAoC;AAClD,cAAc,iCAAiC;AAC/C,cAAc,yCAAyC;AAEvD,gDAAgD;AAChD,cAAc,iBAAyB;AAEvC,SAAS;AACT,SAASA,WAAW,QAAQ,+BAA8B;AAC1D,SAASC,sBAAsB,QAAQ,0CAAyC;AAChF,SAASC,8BAA8B,QAAQ,kDAAiD;AAQhG,OAAO;AACP,SAAQC,kBAAkB,QAAO,oCAAmC;AACpE,SAAQC,iBAAiB,QAAO,mCAAkC;AAClE,SAAQC,kBAAkB,QAAO,oCAAmC;AACpE,SAAQC,GAAG,QAAO,wBAAuB;AACzC,SAAQC,aAAa,QAAO,+BAA8B;AAC1D,SACEC,gBAAgB,EAChBC,eAAe,EACfC,WAAW,EACXC,kBAAkB,EAClBC,kBAAkB,EAClBC,mBAAmB,EACnBC,oBAAoB,EACpBC,mBAAmB,EACnBC,qBAAqB,QAGhB,4BAA2B;AAElC,mBAAmB;AACnB,SACE,kBAAkB;AAClBC,iBAAiB,EACjBC,cAAc,EACdC,0BAA0B,EAC1B,iBAAiB;AACjBC,YAAY,EACZC,kBAAkB,EAClB,gBAAgB;AAChBC,aAAa,EACb,aAAa;AACbC,UAAU,EACV,kBAAkB;AAClBC,YAAY,EACZ,kBAAkB;AAClBC,cAAc,EACdC,eAAe,EACfC,qBAAqB,EACrB,eAAe;AACfC,cAAc,EACd,cAAc;AACdC,mBAAmB,EACnBC,iBAAiB,EACjBC,iBAAiB,EACjB,wBAAwB;AACxBC,eAAe,EACfC,cAAc,EACd,YAAY;AACZC,cAAc,QAaT,+BAA8B;AAErC,QAAQ;AACR,SACEC,eAAe,EACfC,gBAAgB,EAChBC,aAAa,EACbC,YAAY,EACZC,kBAAkB,QAEb,kCAAiC;AAExC,QAAQ;AACR,SACEC,QAAQ,EACRC,eAAe,EACfC,mBAAmB,EACnBC,cAAc,EACdC,aAAa,EACbC,aAAa,EACbC,wBAAwB,EACxBC,cAAc,EACdC,mBAAmB,EACnBC,uBAAuB,EACvBC,aAAa,EACbC,gBAAgB,EAChBC,UAAU,EACVC,kBAAkB,EAClBC,UAAU,QACL,2BAA0B;AAEjC,aAAa;AACb,SACEC,eAAe,QACV,uCAAsC;AAC7C,SAASC,QAAQ,QAA+B,4CAA4C;AAE5F,aAAa;AACb,SAASC,cAAc,QAA0B,sCAAsC;AAGvF,SAAQC,WAAW,QAAO,yBAAwB;AAClD,SAAQC,cAAc,QAA4B,4BAA2B"}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["//Interfaces\nexport * from \"./lib/models/ProgramInterfaces.js\";\nexport * from \"./lib/models/ExerciseInterfaces.js\";\nexport * from \"./lib/models/WorkoutInterfaces.js\";\nexport * from \"./lib/models/UserInterfaces.js\";\nexport * from \"./lib/models/NotificationInterfaces.js\";\n\n//DB Models - Export all models and model arrays\nexport * from \"./lib/dbmodels/index.js\"\n\n//Clients\nexport { EmailClient } from \"./lib/clients/EmailClient.js\"\nexport { PushNotificationClient } from \"./lib/clients/PushNotificationClient.js\"\nexport { FirebasePushNotificationClient } from \"./lib/clients/FirebasePushNotificationClient.js\"\nexport type {\n SendTemplateEmailRequest,\n BatchTemplateEmailRequest,\n EmailResponse,\n} from \"./lib/clients/EmailClient.js\"\nexport type { NotificationPayload } from \"./lib/clients/PushNotificationClient.js\"\n\n//Utils\nexport {AuthenticationUtil} from \"./lib/utils/AuthenticationUtil.js\"\nexport {NotificationsUtil} from \"./lib/utils/NotificationsUtil.js\"\nexport {NotificationClient} from \"./lib/utils/NotificationClient.js\"\nexport {Log} from \"./lib/utils/Logger.js\"\nexport {SecretManager} from \"./lib/utils/SecretManager.js\"\nexport {\n initializeSentry,\n isSentryEnabled,\n scrubObject,\n captureRequestBody,\n extractUserContext,\n buildRequestContext,\n buildResponseContext,\n reportErrorToSentry,\n reportMessageToSentry,\n type ErrorReportOptions,\n type SeverityLevel,\n} from \"./lib/utils/SentryUtil.js\"\n\n//Testing Utilities\nexport {\n createMockContext,\n createMockUser,\n createAuthenticatedContext,\n mockDatabase,\n flushPromises,\n assertions,\n executeRoute,\n type BaseContext,\n type AuthenticatedContext,\n type RouterContext,\n type RouterMiddleware,\n type RouterLayer,\n type RouterLike,\n type SequelizeModelMethods,\n} from \"./lib/testing/testHelpers.js\"\n\n//Config\nexport {\n ConfigValidator,\n BaseConfigSchema,\n CommonSchemas,\n createConfig,\n ConfigurationError,\n type BaseConfig\n} from \"./lib/config/ConfigValidator.js\"\n\n//Errors\nexport {\n AppError,\n ValidationError,\n AuthenticationError,\n ForbiddenError,\n NotFoundError,\n ConflictError,\n UnprocessableEntityError,\n RateLimitError,\n InternalServerError,\n ServiceUnavailableError,\n DatabaseError,\n ExternalAPIError,\n isAppError,\n isOperationalError,\n toAppError\n} from \"./lib/Errors/AppError.js\"\n\n//Middlewares\nexport {\n ErrorMiddleware,\n} from \"./lib/middlewares/ErrorMiddleware.js\"\nexport { validate, type ValidationConfig } from \"./lib/middlewares/ValidationMiddleware.js\";\n\n//Controllers\nexport { BaseController, type RouteConfig } from \"./lib/controllers/BaseController.js\";\n\n\nexport {RedisClient} from \"./lib/classes/Redis.js\"\nexport {DatabaseClient, type DatabaseConfig} from \"./lib/classes/Database.js\""],"names":["EmailClient","PushNotificationClient","FirebasePushNotificationClient","AuthenticationUtil","NotificationsUtil","NotificationClient","Log","SecretManager","initializeSentry","isSentryEnabled","scrubObject","captureRequestBody","extractUserContext","buildRequestContext","buildResponseContext","reportErrorToSentry","reportMessageToSentry","createMockContext","createMockUser","createAuthenticatedContext","mockDatabase","flushPromises","assertions","executeRoute","ConfigValidator","BaseConfigSchema","CommonSchemas","createConfig","ConfigurationError","AppError","ValidationError","AuthenticationError","ForbiddenError","NotFoundError","ConflictError","UnprocessableEntityError","RateLimitError","InternalServerError","ServiceUnavailableError","DatabaseError","ExternalAPIError","isAppError","isOperationalError","toAppError","ErrorMiddleware","validate","BaseController","RedisClient","DatabaseClient"],"mappings":"AAAA,YAAY;AACZ,cAAc,oCAAoC;AAClD,cAAc,qCAAqC;AACnD,cAAc,oCAAoC;AAClD,cAAc,iCAAiC;AAC/C,cAAc,yCAAyC;AAEvD,gDAAgD;AAChD,cAAc,iBAAyB;AAEvC,SAAS;AACT,SAASA,WAAW,QAAQ,+BAA8B;AAC1D,SAASC,sBAAsB,QAAQ,0CAAyC;AAChF,SAASC,8BAA8B,QAAQ,kDAAiD;AAQhG,OAAO;AACP,SAAQC,kBAAkB,QAAO,oCAAmC;AACpE,SAAQC,iBAAiB,QAAO,mCAAkC;AAClE,SAAQC,kBAAkB,QAAO,oCAAmC;AACpE,SAAQC,GAAG,QAAO,wBAAuB;AACzC,SAAQC,aAAa,QAAO,+BAA8B;AAC1D,SACEC,gBAAgB,EAChBC,eAAe,EACfC,WAAW,EACXC,kBAAkB,EAClBC,kBAAkB,EAClBC,mBAAmB,EACnBC,oBAAoB,EACpBC,mBAAmB,EACnBC,qBAAqB,QAGhB,4BAA2B;AAElC,mBAAmB;AACnB,SACEC,iBAAiB,EACjBC,cAAc,EACdC,0BAA0B,EAC1BC,YAAY,EACZC,aAAa,EACbC,UAAU,EACVC,YAAY,QAQP,+BAA8B;AAErC,QAAQ;AACR,SACEC,eAAe,EACfC,gBAAgB,EAChBC,aAAa,EACbC,YAAY,EACZC,kBAAkB,QAEb,kCAAiC;AAExC,QAAQ;AACR,SACEC,QAAQ,EACRC,eAAe,EACfC,mBAAmB,EACnBC,cAAc,EACdC,aAAa,EACbC,aAAa,EACbC,wBAAwB,EACxBC,cAAc,EACdC,mBAAmB,EACnBC,uBAAuB,EACvBC,aAAa,EACbC,gBAAgB,EAChBC,UAAU,EACVC,kBAAkB,EAClBC,UAAU,QACL,2BAA0B;AAEjC,aAAa;AACb,SACEC,eAAe,QACV,uCAAsC;AAC7C,SAASC,QAAQ,QAA+B,4CAA4C;AAE5F,aAAa;AACb,SAASC,cAAc,QAA0B,sCAAsC;AAGvF,SAAQC,WAAW,QAAO,yBAAwB;AAClD,SAAQC,cAAc,QAA4B,4BAA2B"}
@@ -1 +1 @@
1
- {"version":3,"file":"ErrorMiddleware.d.ts","sourceRoot":"","sources":["../../../src/lib/middlewares/ErrorMiddleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AACzC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,QAAQ,EAAc,MAAM,uBAAuB,CAAC;AAW7D,MAAM,WAAW,qBAAqB;IACpC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;IAC9C,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC;IACvD,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,wBAAgB,eAAe,CAAC,MAAM,GAAE,qBAA0B,IAWlD,KAAK,OAAO,EAAE,MAAM,IAAI,mBAkFvC;AA4DD,wBAAgB,eAAe,CAAC,KAAK,EAAE,CAAC,CAAC,QAAQ,GAAG;IAClD,gBAAgB,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACrE,CAQA"}
1
+ {"version":3,"file":"ErrorMiddleware.d.ts","sourceRoot":"","sources":["../../../src/lib/middlewares/ErrorMiddleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AACzC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,QAAQ,EAAc,MAAM,uBAAuB,CAAC;AAa7D,MAAM,WAAW,qBAAqB;IACpC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;IAC9C,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC;IACvD,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,wBAAgB,eAAe,CAAC,MAAM,GAAE,qBAA0B,IAWlD,KAAK,OAAO,EAAE,MAAM,IAAI,mBAmGvC;AA4DD,wBAAgB,eAAe,CAAC,KAAK,EAAE,CAAC,CAAC,QAAQ,GAAG;IAClD,gBAAgB,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACrE,CAQA"}
@@ -1,6 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { AppError, toAppError } from "../Errors/AppError.js";
3
- import { initializeSentry, isSentryEnabled, reportErrorToSentry, reportMessageToSentry } from "../utils/SentryUtil.js";
3
+ import { initializeSentry, isSentryEnabled, reportErrorToSentry, reportMessageToSentry, scrubObject, captureRequestBody } from "../utils/SentryUtil.js";
4
4
  import { Log } from "../utils/Logger.js";
5
5
  const dclogger = Log.getInstance().extend("ErrorMiddleware");
6
6
  export function ErrorMiddleware(config = {}) {
@@ -16,11 +16,13 @@ export function ErrorMiddleware(config = {}) {
16
16
  const requestContext = {
17
17
  method: ctx.method,
18
18
  path: ctx.path,
19
- body: ctx.request.body,
20
- query: ctx.query,
21
- headers: ctx.headers,
19
+ body: captureRequestBody(ctx.request.body),
20
+ query: scrubObject(ctx.query),
21
+ headers: scrubObject(ctx.headers),
22
22
  userUuid: ctx.state.user?.userUuid,
23
- validationErrors: validationErrors.validationErrors
23
+ validationErrors: validationErrors.validationErrors,
24
+ traceId: ctx.state.traceId,
25
+ ip: ctx.ip
24
26
  };
25
27
  // Log validation error with full request context and validation details
26
28
  dclogger.error("Validation error", requestContext);
@@ -36,11 +38,14 @@ export function ErrorMiddleware(config = {}) {
36
38
  const requestContext = {
37
39
  method: ctx.method,
38
40
  path: ctx.path,
39
- body: ctx.request.body,
40
- query: ctx.query,
41
- headers: ctx.headers,
41
+ body: captureRequestBody(ctx.request.body),
42
+ query: scrubObject(ctx.query),
43
+ headers: scrubObject(ctx.headers),
44
+ userUuid: ctx.state.user?.userUuid,
42
45
  error: err instanceof Error ? err.message : String(err),
43
- stack: err instanceof Error ? err.stack : undefined
46
+ stack: err instanceof Error ? err.stack : undefined,
47
+ traceId: ctx.state.traceId,
48
+ ip: ctx.ip
44
49
  };
45
50
  // Log error with full request context
46
51
  dclogger.error("Error processing request", requestContext);
@@ -63,7 +68,17 @@ export function ErrorMiddleware(config = {}) {
63
68
  ctx.status = appError.statusCode;
64
69
  ctx.set("X-Error-Code", appError.code);
65
70
  ctx.type = "application/json";
66
- ctx.body = formatter ? formatter(appError, ctx) : formatErrorResponse(appError, exposeErrorDetails);
71
+ const responseBody = formatter ? formatter(appError, ctx) : formatErrorResponse(appError, exposeErrorDetails);
72
+ ctx.body = responseBody;
73
+ // Log response body for debugging (only in non-production or for server errors)
74
+ if (process.env.NODE_ENV !== "production" || appError.statusCode >= 500) {
75
+ dclogger.error("Error response sent", {
76
+ statusCode: appError.statusCode,
77
+ errorCode: appError.code,
78
+ responseBody: scrubObject(responseBody),
79
+ traceId: ctx.state.traceId
80
+ });
81
+ }
67
82
  }
68
83
  };
69
84
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/lib/middlewares/ErrorMiddleware.ts"],"sourcesContent":["import type { Context, Next } from \"koa\";\nimport { z } from \"zod\";\nimport { AppError, toAppError } from \"../Errors/AppError.js\";\nimport {\n initializeSentry,\n isSentryEnabled,\n reportErrorToSentry,\n reportMessageToSentry,\n} from \"../utils/SentryUtil.js\";\nimport { Log } from \"../utils/Logger.js\";\n\nconst dclogger = Log.getInstance().extend(\"ErrorMiddleware\");\n\nexport interface ErrorMiddlewareConfig {\n exposeErrorDetails?: boolean;\n logErrors?: boolean;\n logger?: (error: Error, ctx: Context) => void;\n formatter?: (error: AppError, ctx: Context) => unknown;\n disableSentry?: boolean;\n}\n\nexport function ErrorMiddleware(config: ErrorMiddlewareConfig = {}) {\n const {\n exposeErrorDetails = false,\n logErrors = true,\n logger,\n formatter,\n disableSentry = false,\n } = config;\n\n initializeSentry();\n\n return async (ctx: Context, next: Next) => {\n try {\n await next();\n } catch (err) {\n let appError: AppError;\n\n if (err instanceof z.ZodError) {\n const validationErrors = formatZodErrors(err);\n const requestContext = {\n method: ctx.method,\n path: ctx.path,\n body: (ctx.request as any).body,\n query: ctx.query,\n headers: ctx.headers,\n userUuid: ctx.state.user?.userUuid,\n validationErrors: validationErrors.validationErrors,\n };\n\n // Log validation error with full request context and validation details\n dclogger.error(\"Validation error\", requestContext);\n\n // Report to Sentry with full context\n if (!disableSentry && isSentryEnabled()) {\n reportMessageToSentry(\n \"Validation error\",\n \"error\",\n {\n request: requestContext,\n validationErrors,\n }\n );\n }\n\n appError = new AppError(\n \"VALIDATION_ERROR\",\n \"Request validation failed\",\n 400,\n validationErrors\n );\n } else {\n const requestContext = {\n method: ctx.method,\n path: ctx.path,\n body: (ctx.request as any).body,\n query: ctx.query,\n headers: ctx.headers,\n error: err instanceof Error ? err.message : String(err),\n stack: err instanceof Error ? err.stack : undefined,\n };\n\n // Log error with full request context\n dclogger.error(\"Error processing request\", requestContext);\n\n appError = toAppError(err);\n }\n\n if (!disableSentry && isSentryEnabled() && appError.statusCode !== 401) {\n reportErrorToSentry(appError, ctx, {\n operational: appError.isOperational,\n errorType: appError.constructor.name,\n statusCode: appError.statusCode,\n });\n }\n\n if (logErrors) {\n if (logger) {\n logger(appError, ctx);\n } else {\n defaultErrorLogger(appError, ctx);\n }\n }\n\n ctx.status = appError.statusCode;\n ctx.set(\"X-Error-Code\", appError.code);\n ctx.type = \"application/json\";\n\n ctx.body = formatter\n ? formatter(appError, ctx)\n : formatErrorResponse(appError, exposeErrorDetails);\n\n }\n };\n}\n\nfunction defaultErrorLogger(error: AppError, ctx: Context): void {\n const isDev = process.env.NODE_ENV === \"development\";\n\n if (error.statusCode >= 500) {\n if (!isDev) {\n const prodLogData = {\n error: {\n code: error.code,\n message: error.message,\n statusCode: error.statusCode,\n },\n request: {\n path: ctx.path,\n },\n user: {\n uuid: ctx.state.user?.userUuid,\n },\n traceId: ctx.state.traceId,\n };\n console.error(\"Server Error:\", JSON.stringify(prodLogData, null, 2));\n } else {\n console.error(\"Server Error:\", error.stack || error.message);\n }\n } else {\n console.warn(\"Client Error:\", JSON.stringify({\n code: error.code,\n message: error.message,\n statusCode: error.statusCode,\n path: ctx.path,\n }));\n }\n}\n\n\nfunction formatErrorResponse(error: AppError, exposeDetails: boolean): unknown {\n const response: {\n code: string;\n message: string;\n details?: unknown;\n stack?: string;\n } = {\n code: error.code,\n message: error.message,\n };\n\n if (exposeDetails || error.statusCode < 500) {\n if (error.details !== undefined) {\n response.details = error.details;\n }\n }\n\n if (exposeDetails && error.stack) {\n response.stack = error.stack;\n }\n\n return response;\n}\n\nexport function formatZodErrors(error: z.ZodError): {\n validationErrors: { path: string; message: string; code: string }[];\n} {\n return {\n validationErrors: error.issues.map((issue) => ({\n path: issue.path.join(\".\"),\n message: issue.message,\n code: issue.code,\n })),\n };\n}"],"names":["z","AppError","toAppError","initializeSentry","isSentryEnabled","reportErrorToSentry","reportMessageToSentry","Log","dclogger","getInstance","extend","ErrorMiddleware","config","exposeErrorDetails","logErrors","logger","formatter","disableSentry","ctx","next","err","appError","ZodError","validationErrors","formatZodErrors","requestContext","method","path","body","request","query","headers","userUuid","state","user","error","Error","message","String","stack","undefined","statusCode","operational","isOperational","errorType","name","defaultErrorLogger","status","set","code","type","formatErrorResponse","isDev","process","env","NODE_ENV","prodLogData","uuid","traceId","console","JSON","stringify","warn","exposeDetails","response","details","issues","map","issue","join"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/lib/middlewares/ErrorMiddleware.ts"],"sourcesContent":["import type { Context, Next } from \"koa\";\nimport { z } from \"zod\";\nimport { AppError, toAppError } from \"../Errors/AppError.js\";\nimport {\n initializeSentry,\n isSentryEnabled,\n reportErrorToSentry,\n reportMessageToSentry,\n scrubObject,\n captureRequestBody,\n} from \"../utils/SentryUtil.js\";\nimport { Log } from \"../utils/Logger.js\";\n\nconst dclogger = Log.getInstance().extend(\"ErrorMiddleware\");\n\nexport interface ErrorMiddlewareConfig {\n exposeErrorDetails?: boolean;\n logErrors?: boolean;\n logger?: (error: Error, ctx: Context) => void;\n formatter?: (error: AppError, ctx: Context) => unknown;\n disableSentry?: boolean;\n}\n\nexport function ErrorMiddleware(config: ErrorMiddlewareConfig = {}) {\n const {\n exposeErrorDetails = false,\n logErrors = true,\n logger,\n formatter,\n disableSentry = false,\n } = config;\n\n initializeSentry();\n\n return async (ctx: Context, next: Next) => {\n try {\n await next();\n } catch (err) {\n let appError: AppError;\n\n if (err instanceof z.ZodError) {\n const validationErrors = formatZodErrors(err);\n const requestContext = {\n method: ctx.method,\n path: ctx.path,\n body: captureRequestBody((ctx.request as any).body),\n query: scrubObject(ctx.query),\n headers: scrubObject(ctx.headers),\n userUuid: ctx.state.user?.userUuid,\n validationErrors: validationErrors.validationErrors,\n traceId: ctx.state.traceId,\n ip: ctx.ip,\n };\n\n // Log validation error with full request context and validation details\n dclogger.error(\"Validation error\", requestContext);\n\n // Report to Sentry with full context\n if (!disableSentry && isSentryEnabled()) {\n reportMessageToSentry(\n \"Validation error\",\n \"error\",\n {\n request: requestContext,\n validationErrors,\n }\n );\n }\n\n appError = new AppError(\n \"VALIDATION_ERROR\",\n \"Request validation failed\",\n 400,\n validationErrors\n );\n } else {\n const requestContext = {\n method: ctx.method,\n path: ctx.path,\n body: captureRequestBody((ctx.request as any).body),\n query: scrubObject(ctx.query),\n headers: scrubObject(ctx.headers),\n userUuid: ctx.state.user?.userUuid,\n error: err instanceof Error ? err.message : String(err),\n stack: err instanceof Error ? err.stack : undefined,\n traceId: ctx.state.traceId,\n ip: ctx.ip,\n };\n\n // Log error with full request context\n dclogger.error(\"Error processing request\", requestContext);\n\n appError = toAppError(err);\n }\n\n if (!disableSentry && isSentryEnabled() && appError.statusCode !== 401) {\n reportErrorToSentry(appError, ctx, {\n operational: appError.isOperational,\n errorType: appError.constructor.name,\n statusCode: appError.statusCode,\n });\n }\n\n if (logErrors) {\n if (logger) {\n logger(appError, ctx);\n } else {\n defaultErrorLogger(appError, ctx);\n }\n }\n\n ctx.status = appError.statusCode;\n ctx.set(\"X-Error-Code\", appError.code);\n ctx.type = \"application/json\";\n\n const responseBody = formatter\n ? formatter(appError, ctx)\n : formatErrorResponse(appError, exposeErrorDetails);\n\n ctx.body = responseBody;\n\n // Log response body for debugging (only in non-production or for server errors)\n if (process.env.NODE_ENV !== \"production\" || appError.statusCode >= 500) {\n dclogger.error(\"Error response sent\", {\n statusCode: appError.statusCode,\n errorCode: appError.code,\n responseBody: scrubObject(responseBody),\n traceId: ctx.state.traceId,\n });\n }\n\n }\n };\n}\n\nfunction defaultErrorLogger(error: AppError, ctx: Context): void {\n const isDev = process.env.NODE_ENV === \"development\";\n\n if (error.statusCode >= 500) {\n if (!isDev) {\n const prodLogData = {\n error: {\n code: error.code,\n message: error.message,\n statusCode: error.statusCode,\n },\n request: {\n path: ctx.path,\n },\n user: {\n uuid: ctx.state.user?.userUuid,\n },\n traceId: ctx.state.traceId,\n };\n console.error(\"Server Error:\", JSON.stringify(prodLogData, null, 2));\n } else {\n console.error(\"Server Error:\", error.stack || error.message);\n }\n } else {\n console.warn(\"Client Error:\", JSON.stringify({\n code: error.code,\n message: error.message,\n statusCode: error.statusCode,\n path: ctx.path,\n }));\n }\n}\n\n\nfunction formatErrorResponse(error: AppError, exposeDetails: boolean): unknown {\n const response: {\n code: string;\n message: string;\n details?: unknown;\n stack?: string;\n } = {\n code: error.code,\n message: error.message,\n };\n\n if (exposeDetails || error.statusCode < 500) {\n if (error.details !== undefined) {\n response.details = error.details;\n }\n }\n\n if (exposeDetails && error.stack) {\n response.stack = error.stack;\n }\n\n return response;\n}\n\nexport function formatZodErrors(error: z.ZodError): {\n validationErrors: { path: string; message: string; code: string }[];\n} {\n return {\n validationErrors: error.issues.map((issue) => ({\n path: issue.path.join(\".\"),\n message: issue.message,\n code: issue.code,\n })),\n };\n}"],"names":["z","AppError","toAppError","initializeSentry","isSentryEnabled","reportErrorToSentry","reportMessageToSentry","scrubObject","captureRequestBody","Log","dclogger","getInstance","extend","ErrorMiddleware","config","exposeErrorDetails","logErrors","logger","formatter","disableSentry","ctx","next","err","appError","ZodError","validationErrors","formatZodErrors","requestContext","method","path","body","request","query","headers","userUuid","state","user","traceId","ip","error","Error","message","String","stack","undefined","statusCode","operational","isOperational","errorType","name","defaultErrorLogger","status","set","code","type","responseBody","formatErrorResponse","process","env","NODE_ENV","errorCode","isDev","prodLogData","uuid","console","JSON","stringify","warn","exposeDetails","response","details","issues","map","issue","join"],"mappings":"AACA,SAASA,CAAC,QAAQ,MAAM;AACxB,SAASC,QAAQ,EAAEC,UAAU,QAAQ,wBAAwB;AAC7D,SACEC,gBAAgB,EAChBC,eAAe,EACfC,mBAAmB,EACnBC,qBAAqB,EACrBC,WAAW,EACXC,kBAAkB,QACb,yBAAyB;AAChC,SAASC,GAAG,QAAQ,qBAAqB;AAEzC,MAAMC,WAAWD,IAAIE,WAAW,GAAGC,MAAM,CAAC;AAU1C,OAAO,SAASC,gBAAgBC,SAAgC,CAAC,CAAC;IAChE,MAAM,EACJC,qBAAqB,KAAK,EAC1BC,YAAY,IAAI,EAChBC,MAAM,EACNC,SAAS,EACTC,gBAAgB,KAAK,EACtB,GAAGL;IAEJX;IAEA,OAAO,OAAOiB,KAAcC;QAC1B,IAAI;YACF,MAAMA;QACR,EAAE,OAAOC,KAAK;YACZ,IAAIC;YAEJ,IAAID,eAAetB,EAAEwB,QAAQ,EAAE;gBAC7B,MAAMC,mBAAmBC,gBAAgBJ;gBACzC,MAAMK,iBAAiB;oBACrBC,QAAQR,IAAIQ,MAAM;oBAClBC,MAAMT,IAAIS,IAAI;oBACdC,MAAMtB,mBAAmB,AAACY,IAAIW,OAAO,CAASD,IAAI;oBAClDE,OAAOzB,YAAYa,IAAIY,KAAK;oBAC5BC,SAAS1B,YAAYa,IAAIa,OAAO;oBAChCC,UAAUd,IAAIe,KAAK,CAACC,IAAI,EAAEF;oBAC1BT,kBAAkBA,iBAAiBA,gBAAgB;oBACnDY,SAASjB,IAAIe,KAAK,CAACE,OAAO;oBAC1BC,IAAIlB,IAAIkB,EAAE;gBACZ;gBAEA,wEAAwE;gBACxE5B,SAAS6B,KAAK,CAAC,oBAAoBZ;gBAEnC,qCAAqC;gBACrC,IAAI,CAACR,iBAAiBf,mBAAmB;oBACvCE,sBACE,oBACA,SACA;wBACEyB,SAASJ;wBACTF;oBACF;gBAEJ;gBAEAF,WAAW,IAAItB,SACX,oBACA,6BACA,KACAwB;YAEN,OAAO;gBACL,MAAME,iBAAiB;oBACrBC,QAAQR,IAAIQ,MAAM;oBAClBC,MAAMT,IAAIS,IAAI;oBACdC,MAAMtB,mBAAmB,AAACY,IAAIW,OAAO,CAASD,IAAI;oBAClDE,OAAOzB,YAAYa,IAAIY,KAAK;oBAC5BC,SAAS1B,YAAYa,IAAIa,OAAO;oBAChCC,UAAUd,IAAIe,KAAK,CAACC,IAAI,EAAEF;oBAC1BK,OAAOjB,eAAekB,QAAQlB,IAAImB,OAAO,GAAGC,OAAOpB;oBACnDqB,OAAOrB,eAAekB,QAAQlB,IAAIqB,KAAK,GAAGC;oBAC1CP,SAASjB,IAAIe,KAAK,CAACE,OAAO;oBAC1BC,IAAIlB,IAAIkB,EAAE;gBACZ;gBAEA,sCAAsC;gBACtC5B,SAAS6B,KAAK,CAAC,4BAA4BZ;gBAE3CJ,WAAWrB,WAAWoB;YACxB;YAEA,IAAI,CAACH,iBAAiBf,qBAAqBmB,SAASsB,UAAU,KAAK,KAAK;gBACtExC,oBAAoBkB,UAAUH,KAAK;oBACjC0B,aAAavB,SAASwB,aAAa;oBACnCC,WAAWzB,SAAS,WAAW,CAAC0B,IAAI;oBACpCJ,YAAYtB,SAASsB,UAAU;gBACjC;YACF;YAEA,IAAI7B,WAAW;gBACb,IAAIC,QAAQ;oBACVA,OAAOM,UAAUH;gBACnB,OAAO;oBACL8B,mBAAmB3B,UAAUH;gBAC/B;YACF;YAEAA,IAAI+B,MAAM,GAAG5B,SAASsB,UAAU;YAChCzB,IAAIgC,GAAG,CAAC,gBAAgB7B,SAAS8B,IAAI;YACrCjC,IAAIkC,IAAI,GAAG;YAEX,MAAMC,eAAerC,YACfA,UAAUK,UAAUH,OACpBoC,oBAAoBjC,UAAUR;YAEpCK,IAAIU,IAAI,GAAGyB;YAEX,gFAAgF;YAChF,IAAIE,QAAQC,GAAG,CAACC,QAAQ,KAAK,gBAAgBpC,SAASsB,UAAU,IAAI,KAAK;gBACvEnC,SAAS6B,KAAK,CAAC,uBAAuB;oBACpCM,YAAYtB,SAASsB,UAAU;oBAC/Be,WAAWrC,SAAS8B,IAAI;oBACxBE,cAAchD,YAAYgD;oBAC1BlB,SAASjB,IAAIe,KAAK,CAACE,OAAO;gBAC5B;YACF;QAEF;IACF;AACF;AAEA,SAASa,mBAAmBX,KAAe,EAAEnB,GAAY;IACvD,MAAMyC,QAAQJ,QAAQC,GAAG,CAACC,QAAQ,KAAK;IAEvC,IAAIpB,MAAMM,UAAU,IAAI,KAAK;QAC3B,IAAI,CAACgB,OAAO;YACV,MAAMC,cAAc;gBAClBvB,OAAO;oBACLc,MAAMd,MAAMc,IAAI;oBAChBZ,SAASF,MAAME,OAAO;oBACtBI,YAAYN,MAAMM,UAAU;gBAC9B;gBACAd,SAAS;oBACPF,MAAMT,IAAIS,IAAI;gBAChB;gBACAO,MAAM;oBACJ2B,MAAM3C,IAAIe,KAAK,CAACC,IAAI,EAAEF;gBACxB;gBACAG,SAASjB,IAAIe,KAAK,CAACE,OAAO;YAC5B;YACA2B,QAAQzB,KAAK,CAAC,iBAAiB0B,KAAKC,SAAS,CAACJ,aAAa,MAAM;QACnE,OAAO;YACLE,QAAQzB,KAAK,CAAC,iBAAiBA,MAAMI,KAAK,IAAIJ,MAAME,OAAO;QAC7D;IACF,OAAO;QACLuB,QAAQG,IAAI,CAAC,iBAAiBF,KAAKC,SAAS,CAAC;YAC3Cb,MAAMd,MAAMc,IAAI;YAChBZ,SAASF,MAAME,OAAO;YACtBI,YAAYN,MAAMM,UAAU;YAC5BhB,MAAMT,IAAIS,IAAI;QAChB;IACF;AACF;AAGA,SAAS2B,oBAAoBjB,KAAe,EAAE6B,aAAsB;IAClE,MAAMC,WAKF;QACAhB,MAAMd,MAAMc,IAAI;QAChBZ,SAASF,MAAME,OAAO;IAC1B;IAEA,IAAI2B,iBAAiB7B,MAAMM,UAAU,GAAG,KAAK;QAC3C,IAAIN,MAAM+B,OAAO,KAAK1B,WAAW;YAC/ByB,SAASC,OAAO,GAAG/B,MAAM+B,OAAO;QAClC;IACF;IAEA,IAAIF,iBAAiB7B,MAAMI,KAAK,EAAE;QAChC0B,SAAS1B,KAAK,GAAGJ,MAAMI,KAAK;IAC9B;IAEA,OAAO0B;AACT;AAEA,OAAO,SAAS3C,gBAAgBa,KAAiB;IAG/C,OAAO;QACLd,kBAAkBc,MAAMgC,MAAM,CAACC,GAAG,CAAC,CAACC,QAAW,CAAA;gBAC7C5C,MAAM4C,MAAM5C,IAAI,CAAC6C,IAAI,CAAC;gBACtBjC,SAASgC,MAAMhC,OAAO;gBACtBY,MAAMoB,MAAMpB,IAAI;YAClB,CAAA;IACF;AACF"}
@@ -1,5 +1,4 @@
1
1
  import type { UserTypes } from '../models/UserInterfaces.js';
2
- export type Mock = any;
3
2
  export interface BaseContext {
4
3
  request: {
5
4
  body?: unknown;
@@ -43,131 +42,6 @@ export declare const mockDatabase: {
43
42
  mockModel<T = unknown>(methods?: Partial<SequelizeModelMethods<T>>): SequelizeModelMethods<T>;
44
43
  };
45
44
  export declare function flushPromises(): Promise<void>;
46
- /**
47
- * ============================================================================
48
- * TEST DATA FACTORIES
49
- * Following industry best practices from Testing Blueprint
50
- * ============================================================================
51
- */
52
- /**
53
- * Constants for testing - avoids magic values
54
- */
55
- export declare const TEST_CONSTANTS: {
56
- readonly VALID_UUID: "123e4567-e89b-12d3-a456-426614174000";
57
- readonly INVALID_UUID: "invalid-uuid";
58
- readonly VALID_TIMEZONE: "America/New_York";
59
- readonly INVALID_TIMEZONE: "Invalid/Timezone";
60
- readonly DEFAULT_TIMEZONE: "UTC";
61
- readonly TEST_DATE: "2026-02-25T10:00:00Z";
62
- readonly WEEK_START: "2026-02-23";
63
- readonly MAX_JSON_SIZE: number;
64
- };
65
- /**
66
- * Mock file upload structure (multer format)
67
- */
68
- export interface MockFile {
69
- fieldname: string;
70
- originalname: string;
71
- encoding: string;
72
- mimetype: string;
73
- buffer: Buffer;
74
- size: number;
75
- }
76
- /**
77
- * Creates a mock file for upload testing
78
- */
79
- export declare function createMockFile(overrides?: Partial<MockFile>): MockFile;
80
- /**
81
- * Creates multiple mock files
82
- */
83
- export declare function createMockFiles(count: number): MockFile[];
84
- /**
85
- * Mock transaction for database testing
86
- */
87
- export interface MockTransaction {
88
- commit: Mock;
89
- rollback: Mock;
90
- finished?: string;
91
- }
92
- /**
93
- * Creates a mock Sequelize transaction
94
- */
95
- export declare function createMockTransaction(): MockTransaction;
96
- /**
97
- * ============================================================================
98
- * MOCK CONFIGURATIONS
99
- * Pre-configured mocks for common testing scenarios
100
- * ============================================================================
101
- */
102
- /**
103
- * Database mock configuration
104
- */
105
- export interface DatabaseMocks {
106
- findOne: Mock;
107
- findOrCreate: Mock;
108
- findByPk: Mock;
109
- findAll: Mock;
110
- create: Mock;
111
- update: Mock;
112
- upsert: Mock;
113
- bulkCreate: Mock;
114
- destroy: Mock;
115
- reset: () => void;
116
- restore: () => void;
117
- }
118
- /**
119
- * Creates a set of database operation mocks with reset/restore functionality
120
- */
121
- export declare function setupDatabaseMocks(): DatabaseMocks;
122
- /**
123
- * Time-related mock utilities
124
- */
125
- export interface TimeMocks {
126
- setTime: (date: string | Date) => void;
127
- advanceTime: (ms: number) => void;
128
- restore: () => void;
129
- }
130
- /**
131
- * Sets up fake timers for timezone testing
132
- * Usage:
133
- * ```typescript
134
- * describe('My test', () => {
135
- * const timeMocks = setupTimeMocks();
136
- *
137
- * it('test with fixed time', () => {
138
- * timeMocks.setTime('2026-02-25T10:00:00Z');
139
- * // ... test code
140
- * });
141
- * });
142
- * ```
143
- */
144
- export declare function setupTimeMocks(): TimeMocks;
145
- /**
146
- * Mock error instances for testing error handling
147
- */
148
- export declare class MockValidationError extends Error {
149
- issues: any[];
150
- constructor(message: string, issues?: any[]);
151
- }
152
- export declare class MockNotFoundError extends Error {
153
- constructor(message: string);
154
- }
155
- export declare class MockDatabaseError extends Error {
156
- constructor(message: string);
157
- }
158
- /**
159
- * Helper to create a typed mock function
160
- */
161
- export declare function createTypedMock(): Mock;
162
- /**
163
- * Helper to create a typed spy on a prototype method
164
- * Usage:
165
- * ```typescript
166
- * const mockMethod = spyOnPrototype(MyService.prototype, 'methodName');
167
- * mockMethod.mockResolvedValue({ success: true });
168
- * ```
169
- */
170
- export declare function spyOnPrototype<T, K extends keyof T>(prototype: T, method: K): Mock;
171
45
  export declare const assertions: {
172
46
  assertDefined<T>(value: T | null | undefined, message?: string): asserts value is T;
173
47
  assertStatusCode(ctx: BaseContext | {
@@ -1 +1 @@
1
- {"version":3,"file":"testHelpers.d.ts","sourceRoot":"","sources":["../../../src/lib/testing/testHelpers.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"testHelpers.d.ts","sourceRoot":"","sources":["../../../src/lib/testing/testHelpers.ts"],"names":[],"mappings":"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"}
@@ -73,167 +73,6 @@ export const mockDatabase = {
73
73
  export async function flushPromises() {
74
74
  return new Promise((resolve)=>setImmediate(resolve));
75
75
  }
76
- /**
77
- * ============================================================================
78
- * TEST DATA FACTORIES
79
- * Following industry best practices from Testing Blueprint
80
- * ============================================================================
81
- */ /**
82
- * Constants for testing - avoids magic values
83
- */ export const TEST_CONSTANTS = {
84
- VALID_UUID: '123e4567-e89b-12d3-a456-426614174000',
85
- INVALID_UUID: 'invalid-uuid',
86
- VALID_TIMEZONE: 'America/New_York',
87
- INVALID_TIMEZONE: 'Invalid/Timezone',
88
- DEFAULT_TIMEZONE: 'UTC',
89
- TEST_DATE: '2026-02-25T10:00:00Z',
90
- WEEK_START: '2026-02-23',
91
- MAX_JSON_SIZE: 1024 * 1024
92
- };
93
- /**
94
- * Creates a mock file for upload testing
95
- */ export function createMockFile(overrides = {}) {
96
- return {
97
- fieldname: 'photos',
98
- originalname: 'test-photo.jpg',
99
- encoding: '7bit',
100
- mimetype: 'image/jpeg',
101
- buffer: Buffer.from('fake-image-data'),
102
- size: 1024,
103
- ...overrides
104
- };
105
- }
106
- /**
107
- * Creates multiple mock files
108
- */ export function createMockFiles(count) {
109
- return Array.from({
110
- length: count
111
- }, (_, i)=>createMockFile({
112
- originalname: `test-photo-${i}.jpg`,
113
- size: 1024 * (i + 1)
114
- }));
115
- }
116
- /**
117
- * Creates a mock Sequelize transaction
118
- */ export function createMockTransaction() {
119
- const mockFn = globalThis.jest?.fn || (()=>{
120
- throw new Error('jest.fn is not available. Make sure jest is properly configured.');
121
- });
122
- return {
123
- commit: mockFn().mockResolvedValue(undefined),
124
- rollback: mockFn().mockResolvedValue(undefined)
125
- };
126
- }
127
- /**
128
- * Creates a set of database operation mocks with reset/restore functionality
129
- */ export function setupDatabaseMocks() {
130
- // Note: jest must be imported in the test file for this to work
131
- const mockFn = globalThis.jest?.fn || (()=>{
132
- throw new Error('jest.fn is not available. Make sure jest is properly configured.');
133
- });
134
- const mocks = {
135
- findOne: mockFn(),
136
- findOrCreate: mockFn(),
137
- findByPk: mockFn(),
138
- findAll: mockFn(),
139
- create: mockFn(),
140
- update: mockFn(),
141
- upsert: mockFn(),
142
- bulkCreate: mockFn(),
143
- destroy: mockFn()
144
- };
145
- return {
146
- ...mocks,
147
- reset: ()=>{
148
- Object.values(mocks).forEach((mock)=>mock.mockReset?.());
149
- },
150
- restore: ()=>{
151
- Object.values(mocks).forEach((mock)=>mock.mockRestore?.());
152
- }
153
- };
154
- }
155
- /**
156
- * Sets up fake timers for timezone testing
157
- * Usage:
158
- * ```typescript
159
- * describe('My test', () => {
160
- * const timeMocks = setupTimeMocks();
161
- *
162
- * it('test with fixed time', () => {
163
- * timeMocks.setTime('2026-02-25T10:00:00Z');
164
- * // ... test code
165
- * });
166
- * });
167
- * ```
168
- */ export function setupTimeMocks() {
169
- const jestGlobal = globalThis.jest;
170
- const beforeEachGlobal = globalThis.beforeEach;
171
- const afterEachGlobal = globalThis.afterEach;
172
- if (beforeEachGlobal) {
173
- beforeEachGlobal(()=>{
174
- jestGlobal?.useFakeTimers();
175
- });
176
- }
177
- if (afterEachGlobal) {
178
- afterEachGlobal(()=>{
179
- jestGlobal?.useRealTimers();
180
- });
181
- }
182
- return {
183
- setTime: (date)=>{
184
- jestGlobal?.setSystemTime(new Date(date));
185
- },
186
- advanceTime: (ms)=>{
187
- jestGlobal?.advanceTimersByTime(ms);
188
- },
189
- restore: ()=>{
190
- jestGlobal?.useRealTimers();
191
- }
192
- };
193
- }
194
- /**
195
- * Mock error instances for testing error handling
196
- */ export class MockValidationError extends Error {
197
- issues;
198
- constructor(message, issues = []){
199
- super(message), this.issues = issues;
200
- this.name = 'ValidationError';
201
- }
202
- }
203
- export class MockNotFoundError extends Error {
204
- constructor(message){
205
- super(message);
206
- this.name = 'NotFoundError';
207
- }
208
- }
209
- export class MockDatabaseError extends Error {
210
- constructor(message){
211
- super(message);
212
- this.name = 'SequelizeDatabaseError';
213
- }
214
- }
215
- /**
216
- * Helper to create a typed mock function
217
- */ export function createTypedMock() {
218
- const mockFn = globalThis.jest?.fn || (()=>{
219
- throw new Error('jest.fn is not available. Make sure jest is properly configured.');
220
- });
221
- return mockFn();
222
- }
223
- /**
224
- * Helper to create a typed spy on a prototype method
225
- * Usage:
226
- * ```typescript
227
- * const mockMethod = spyOnPrototype(MyService.prototype, 'methodName');
228
- * mockMethod.mockResolvedValue({ success: true });
229
- * ```
230
- */ export function spyOnPrototype(prototype, method) {
231
- const jestGlobal = globalThis.jest;
232
- if (!jestGlobal?.spyOn) {
233
- throw new Error('jest.spyOn is not available. Make sure jest is properly configured.');
234
- }
235
- return jestGlobal.spyOn(prototype, method);
236
- }
237
76
  export const assertions = {
238
77
  assertDefined (value, message) {
239
78
  if (value === null || value === undefined) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/lib/testing/testHelpers.ts"],"sourcesContent":["import type { UserTypes } from '../models/UserInterfaces.js';\n\n// Mock type definition to avoid jest-mock dependency\nexport type Mock = any;\n\n\nexport interface BaseContext {\n request: {\n body?: unknown;\n headers?: Record<string, string | string[] | undefined>;\n files?: unknown;\n };\n response: {\n status: number;\n body?: unknown;\n };\n params?: Record<string, string>;\n query?: Record<string, string | string[] | undefined>;\n state: Record<string, unknown>;\n status: number;\n body?: unknown;\n headers: Record<string, string | string[] | undefined>;\n method?: string;\n path?: string;\n get: (field: string) => string | string[] | undefined;\n set: (field: string, value: string) => void;\n}\n\n\nexport function createMockContext<T extends BaseContext = BaseContext>(\n overrides: Partial<T> = {},\n): T {\n const ctx: BaseContext = {\n request: {\n body: {},\n headers: {},\n ...overrides.request,\n },\n response: {\n status: 200,\n body: undefined,\n ...overrides.response,\n },\n params: overrides.params || {},\n query: overrides.query || {},\n state: overrides.state || {},\n status: overrides.status || 200,\n body: overrides.body,\n headers: overrides.headers || {},\n method: overrides.method || 'GET',\n path: overrides.path || '/',\n get: (field: string) => {\n return ctx.headers[field.toLowerCase()];\n },\n set: (field: string, value: string) => {\n ctx.headers[field.toLowerCase()] = value;\n },\n };\n\n return { ...ctx, ...overrides } as T;\n}\n\n\nexport function createMockUser(overrides: Partial<UserTypes> = {}): UserTypes {\n return {\n userUuid: overrides.userUuid || 'test-user-uuid',\n email: overrides.email || 'test@example.com',\n firstName: overrides.firstName || 'Test',\n lastName: overrides.lastName || 'User',\n avatar: overrides.avatar || '1',\n role: overrides.role || 'user',\n isSubscriptionActive: overrides.isSubscriptionActive ?? true,\n ...overrides,\n };\n}\n\n\nexport interface AuthenticatedContext extends BaseContext {\n state: {\n user: UserTypes;\n [key: string]: unknown;\n };\n}\n\n\nexport function createAuthenticatedContext<T extends BaseContext = AuthenticatedContext>(\n userOverrides: Partial<UserTypes> = {},\n contextOverrides: Partial<T> = {},\n): T {\n const user = createMockUser(userOverrides);\n\n return createMockContext<T>({\n ...contextOverrides,\n state: {\n user,\n ...(contextOverrides.state || {}),\n },\n headers: {\n authorization: 'Bearer mock-token',\n ...(contextOverrides.headers || {}),\n },\n } as Partial<T>);\n}\n\nexport interface SequelizeModelMethods<T = unknown> {\n findOne: ((options?: unknown) => Promise<T | null>) | undefined;\n findAll: ((options?: unknown) => Promise<T[]>) | undefined;\n findByPk: ((id: string | number, options?: unknown) => Promise<T | null>) | undefined;\n create: ((values: Partial<T>, options?: unknown) => Promise<T>) | undefined;\n update: ((values: Partial<T>, options?: unknown) => Promise<[number, T[]]>) | undefined;\n destroy: ((options?: unknown) => Promise<number>) | undefined;\n count: ((options?: unknown) => Promise<number>) | undefined;\n}\n\n\nexport const mockDatabase = {\n\n mockModel<T = unknown>(\n methods: Partial<SequelizeModelMethods<T>> = {},\n ): SequelizeModelMethods<T> {\n return {\n findOne: undefined,\n findAll: undefined,\n findByPk: undefined,\n create: undefined,\n update: undefined,\n destroy: undefined,\n count: undefined,\n ...methods,\n };\n },\n};\n\n\nexport async function flushPromises(): Promise<void> {\n return new Promise((resolve) => setImmediate(resolve));\n}\n\n/**\n * ============================================================================\n * TEST DATA FACTORIES\n * Following industry best practices from Testing Blueprint\n * ============================================================================\n */\n\n/**\n * Constants for testing - avoids magic values\n */\nexport const TEST_CONSTANTS = {\n VALID_UUID: '123e4567-e89b-12d3-a456-426614174000',\n INVALID_UUID: 'invalid-uuid',\n VALID_TIMEZONE: 'America/New_York',\n INVALID_TIMEZONE: 'Invalid/Timezone',\n DEFAULT_TIMEZONE: 'UTC',\n TEST_DATE: '2026-02-25T10:00:00Z',\n WEEK_START: '2026-02-23',\n MAX_JSON_SIZE: 1024 * 1024, // 1MB\n} as const;\n\n/**\n * Mock file upload structure (multer format)\n */\nexport interface MockFile {\n fieldname: string;\n originalname: string;\n encoding: string;\n mimetype: string;\n buffer: Buffer;\n size: number;\n}\n\n/**\n * Creates a mock file for upload testing\n */\nexport function createMockFile(overrides: Partial<MockFile> = {}): MockFile {\n return {\n fieldname: 'photos',\n originalname: 'test-photo.jpg',\n encoding: '7bit',\n mimetype: 'image/jpeg',\n buffer: Buffer.from('fake-image-data'),\n size: 1024,\n ...overrides,\n };\n}\n\n/**\n * Creates multiple mock files\n */\nexport function createMockFiles(count: number): MockFile[] {\n return Array.from({ length: count }, (_, i) =>\n createMockFile({\n originalname: `test-photo-${i}.jpg`,\n size: 1024 * (i + 1),\n }),\n );\n}\n\n/**\n * Mock transaction for database testing\n */\nexport interface MockTransaction {\n commit: Mock;\n rollback: Mock;\n finished?: string;\n}\n\n/**\n * Creates a mock Sequelize transaction\n */\nexport function createMockTransaction(): MockTransaction {\n const mockFn = (globalThis as any).jest?.fn || (() => {\n throw new Error('jest.fn is not available. Make sure jest is properly configured.');\n });\n\n return {\n commit: mockFn().mockResolvedValue(undefined),\n rollback: mockFn().mockResolvedValue(undefined),\n };\n}\n\n/**\n * ============================================================================\n * MOCK CONFIGURATIONS\n * Pre-configured mocks for common testing scenarios\n * ============================================================================\n */\n\n/**\n * Database mock configuration\n */\nexport interface DatabaseMocks {\n findOne: Mock;\n findOrCreate: Mock;\n findByPk: Mock;\n findAll: Mock;\n create: Mock;\n update: Mock;\n upsert: Mock;\n bulkCreate: Mock;\n destroy: Mock;\n reset: () => void;\n restore: () => void;\n}\n\n/**\n * Creates a set of database operation mocks with reset/restore functionality\n */\nexport function setupDatabaseMocks(): DatabaseMocks {\n // Note: jest must be imported in the test file for this to work\n const mockFn = (globalThis as any).jest?.fn || (() => {\n throw new Error('jest.fn is not available. Make sure jest is properly configured.');\n });\n\n const mocks = {\n findOne: mockFn(),\n findOrCreate: mockFn(),\n findByPk: mockFn(),\n findAll: mockFn(),\n create: mockFn(),\n update: mockFn(),\n upsert: mockFn(),\n bulkCreate: mockFn(),\n destroy: mockFn(),\n };\n\n return {\n ...mocks,\n reset: () => {\n Object.values(mocks).forEach((mock) => mock.mockReset?.());\n },\n restore: () => {\n Object.values(mocks).forEach((mock) => mock.mockRestore?.());\n },\n };\n}\n\n/**\n * Time-related mock utilities\n */\nexport interface TimeMocks {\n setTime: (date: string | Date) => void;\n advanceTime: (ms: number) => void;\n restore: () => void;\n}\n\n/**\n * Sets up fake timers for timezone testing\n * Usage:\n * ```typescript\n * describe('My test', () => {\n * const timeMocks = setupTimeMocks();\n *\n * it('test with fixed time', () => {\n * timeMocks.setTime('2026-02-25T10:00:00Z');\n * // ... test code\n * });\n * });\n * ```\n */\nexport function setupTimeMocks(): TimeMocks {\n const jestGlobal = (globalThis as any).jest;\n const beforeEachGlobal = (globalThis as any).beforeEach;\n const afterEachGlobal = (globalThis as any).afterEach;\n\n if (beforeEachGlobal) {\n beforeEachGlobal(() => {\n jestGlobal?.useFakeTimers();\n });\n }\n\n if (afterEachGlobal) {\n afterEachGlobal(() => {\n jestGlobal?.useRealTimers();\n });\n }\n\n return {\n setTime: (date: string | Date) => {\n jestGlobal?.setSystemTime(new Date(date));\n },\n advanceTime: (ms: number) => {\n jestGlobal?.advanceTimersByTime(ms);\n },\n restore: () => {\n jestGlobal?.useRealTimers();\n },\n };\n}\n\n/**\n * Mock error instances for testing error handling\n */\nexport class MockValidationError extends Error {\n constructor(\n message: string,\n public issues: any[] = [],\n ) {\n super(message);\n this.name = 'ValidationError';\n }\n}\n\nexport class MockNotFoundError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'NotFoundError';\n }\n}\n\nexport class MockDatabaseError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'SequelizeDatabaseError';\n }\n}\n\n/**\n * Helper to create a typed mock function\n */\nexport function createTypedMock(): Mock {\n const mockFn = (globalThis as any).jest?.fn || (() => {\n throw new Error('jest.fn is not available. Make sure jest is properly configured.');\n });\n return mockFn() as Mock;\n}\n\n/**\n * Helper to create a typed spy on a prototype method\n * Usage:\n * ```typescript\n * const mockMethod = spyOnPrototype(MyService.prototype, 'methodName');\n * mockMethod.mockResolvedValue({ success: true });\n * ```\n */\nexport function spyOnPrototype<T, K extends keyof T>(\n prototype: T,\n method: K,\n): Mock {\n const jestGlobal = (globalThis as any).jest;\n if (!jestGlobal?.spyOn) {\n throw new Error('jest.spyOn is not available. Make sure jest is properly configured.');\n }\n return jestGlobal.spyOn(prototype as any, method as any) as any;\n}\n\n\nexport const assertions = {\n\n assertDefined<T>(value: T | null | undefined, message?: string): asserts value is T {\n if (value === null || value === undefined) {\n throw new Error(message || 'Expected value to be defined');\n }\n },\n\n\n assertStatusCode(ctx: BaseContext | { status: number; body?: unknown }, expected: number): void {\n if (ctx.status !== expected) {\n throw new Error(\n `Expected status ${expected} but got ${ctx.status}. Body: ${JSON.stringify(ctx.body)}`,\n );\n }\n },\n\n assertResponseShape(\n body: unknown,\n expectedKeys: string[],\n ): asserts body is Record<string, unknown> {\n if (typeof body !== 'object' || body === null) {\n throw new Error('Expected body to be an object');\n }\n const actualKeys = Object.keys(body);\n const missingKeys = expectedKeys.filter((key) => !actualKeys.includes(key));\n if (missingKeys.length > 0) {\n throw new Error(\n `Missing expected keys in response: ${missingKeys.join(', ')}. Got: ${actualKeys.join(', ')}`,\n );\n }\n },\n\n\n assertExists<T>(value: T | null | undefined, message?: string): asserts value is T {\n if (value === null || value === undefined) {\n throw new Error(message || 'Expected value to exist');\n }\n },\n\n assertType<T>(value: unknown, type: string, message?: string): asserts value is T {\n if (typeof value !== type) {\n throw new Error(message || `Expected value to be of type ${type}, got ${typeof value}`);\n }\n },\n\n validateObjectProperties<T extends Record<string, unknown>>(\n obj: unknown,\n expectedProps: (keyof T)[],\n ): obj is T {\n if (typeof obj !== 'object' || obj === null) {\n return false;\n }\n return expectedProps.every((prop) => prop in obj);\n },\n};\n\nexport interface RouterContext extends BaseContext {\n params: Record<string, string>;\n router?: unknown;\n _matchedRoute?: string;\n _matchedRouteName?: string;\n}\n\n\nexport type RouterMiddleware<TContext = BaseContext> = (\n ctx: TContext,\n next: () => Promise<void>\n) => Promise<void> | void;\n\n\nexport interface RouterLayer<TContext = BaseContext> {\n path: string | RegExp;\n methods: string[];\n stack: RouterMiddleware<TContext>[];\n name?: string | null;\n}\n\n\nexport interface RouterLike<TContext = BaseContext> {\n stack: RouterLayer<TContext>[];\n}\n\nexport async function executeRoute<TContext extends BaseContext = BaseContext>(\n router: { stack: { path: string | RegExp; methods: string[]; stack: unknown[] }[] },\n path: string,\n method: string,\n ctx: TContext,\n): Promise<void> {\n const route = router.stack.find(\n (layer) => layer.path === path && layer.methods.includes(method)\n );\n\n if (!route) {\n throw new Error(`Route not found: ${method} ${path}`);\n }\n\n // Cast context to include router properties\n // We add these properties dynamically, so TypeScript needs to trust us here\n const routerCtx = ctx as TContext & RouterContext;\n if (!routerCtx.params) {\n routerCtx.params = {};\n }\n if (!routerCtx.router) {\n routerCtx.router = router;\n }\n if (!routerCtx._matchedRoute) {\n routerCtx._matchedRoute = path;\n }\n\n // Execute all middlewares in the stack (validation, then handler)\n // Build the middleware chain from right to left\n let index = -1;\n\n const dispatch = async (i: number): Promise<void> => {\n if (i <= index) {\n throw new Error('next() called multiple times');\n }\n index = i;\n\n if (i >= route.stack.length) {\n return;\n }\n\n const middleware = route.stack[i] as (ctx: unknown, next: () => Promise<void>) => Promise<void>;\n return await middleware(routerCtx, () => dispatch(i + 1));\n };\n\n await dispatch(0);\n}\n"],"names":["createMockContext","overrides","ctx","request","body","headers","response","status","undefined","params","query","state","method","path","get","field","toLowerCase","set","value","createMockUser","userUuid","email","firstName","lastName","avatar","role","isSubscriptionActive","createAuthenticatedContext","userOverrides","contextOverrides","user","authorization","mockDatabase","mockModel","methods","findOne","findAll","findByPk","create","update","destroy","count","flushPromises","Promise","resolve","setImmediate","TEST_CONSTANTS","VALID_UUID","INVALID_UUID","VALID_TIMEZONE","INVALID_TIMEZONE","DEFAULT_TIMEZONE","TEST_DATE","WEEK_START","MAX_JSON_SIZE","createMockFile","fieldname","originalname","encoding","mimetype","buffer","Buffer","from","size","createMockFiles","Array","length","_","i","createMockTransaction","mockFn","globalThis","jest","fn","Error","commit","mockResolvedValue","rollback","setupDatabaseMocks","mocks","findOrCreate","upsert","bulkCreate","reset","Object","values","forEach","mock","mockReset","restore","mockRestore","setupTimeMocks","jestGlobal","beforeEachGlobal","beforeEach","afterEachGlobal","afterEach","useFakeTimers","useRealTimers","setTime","date","setSystemTime","Date","advanceTime","ms","advanceTimersByTime","MockValidationError","message","issues","name","MockNotFoundError","MockDatabaseError","createTypedMock","spyOnPrototype","prototype","spyOn","assertions","assertDefined","assertStatusCode","expected","JSON","stringify","assertResponseShape","expectedKeys","actualKeys","keys","missingKeys","filter","key","includes","join","assertExists","assertType","type","validateObjectProperties","obj","expectedProps","every","prop","executeRoute","router","route","stack","find","layer","routerCtx","_matchedRoute","index","dispatch","middleware"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/lib/testing/testHelpers.ts"],"sourcesContent":["import type { UserTypes } from '../models/UserInterfaces.js';\n\n\nexport interface BaseContext {\n request: {\n body?: unknown;\n headers?: Record<string, string | string[] | undefined>;\n files?: unknown;\n };\n response: {\n status: number;\n body?: unknown;\n };\n params?: Record<string, string>;\n query?: Record<string, string | string[] | undefined>;\n state: Record<string, unknown>;\n status: number;\n body?: unknown;\n headers: Record<string, string | string[] | undefined>;\n method?: string;\n path?: string;\n get: (field: string) => string | string[] | undefined;\n set: (field: string, value: string) => void;\n}\n\n\nexport function createMockContext<T extends BaseContext = BaseContext>(\n overrides: Partial<T> = {},\n): T {\n const ctx: BaseContext = {\n request: {\n body: {},\n headers: {},\n ...overrides.request,\n },\n response: {\n status: 200,\n body: undefined,\n ...overrides.response,\n },\n params: overrides.params || {},\n query: overrides.query || {},\n state: overrides.state || {},\n status: overrides.status || 200,\n body: overrides.body,\n headers: overrides.headers || {},\n method: overrides.method || 'GET',\n path: overrides.path || '/',\n get: (field: string) => {\n return ctx.headers[field.toLowerCase()];\n },\n set: (field: string, value: string) => {\n ctx.headers[field.toLowerCase()] = value;\n },\n };\n\n return { ...ctx, ...overrides } as T;\n}\n\n\nexport function createMockUser(overrides: Partial<UserTypes> = {}): UserTypes {\n return {\n userUuid: overrides.userUuid || 'test-user-uuid',\n email: overrides.email || 'test@example.com',\n firstName: overrides.firstName || 'Test',\n lastName: overrides.lastName || 'User',\n avatar: overrides.avatar || '1',\n role: overrides.role || 'user',\n isSubscriptionActive: overrides.isSubscriptionActive ?? true,\n ...overrides,\n };\n}\n\n\nexport interface AuthenticatedContext extends BaseContext {\n state: {\n user: UserTypes;\n [key: string]: unknown;\n };\n}\n\n\nexport function createAuthenticatedContext<T extends BaseContext = AuthenticatedContext>(\n userOverrides: Partial<UserTypes> = {},\n contextOverrides: Partial<T> = {},\n): T {\n const user = createMockUser(userOverrides);\n\n return createMockContext<T>({\n ...contextOverrides,\n state: {\n user,\n ...(contextOverrides.state || {}),\n },\n headers: {\n authorization: 'Bearer mock-token',\n ...(contextOverrides.headers || {}),\n },\n } as Partial<T>);\n}\n\nexport interface SequelizeModelMethods<T = unknown> {\n findOne: ((options?: unknown) => Promise<T | null>) | undefined;\n findAll: ((options?: unknown) => Promise<T[]>) | undefined;\n findByPk: ((id: string | number, options?: unknown) => Promise<T | null>) | undefined;\n create: ((values: Partial<T>, options?: unknown) => Promise<T>) | undefined;\n update: ((values: Partial<T>, options?: unknown) => Promise<[number, T[]]>) | undefined;\n destroy: ((options?: unknown) => Promise<number>) | undefined;\n count: ((options?: unknown) => Promise<number>) | undefined;\n}\n\n\nexport const mockDatabase = {\n\n mockModel<T = unknown>(\n methods: Partial<SequelizeModelMethods<T>> = {},\n ): SequelizeModelMethods<T> {\n return {\n findOne: undefined,\n findAll: undefined,\n findByPk: undefined,\n create: undefined,\n update: undefined,\n destroy: undefined,\n count: undefined,\n ...methods,\n };\n },\n};\n\n\nexport async function flushPromises(): Promise<void> {\n return new Promise((resolve) => setImmediate(resolve));\n}\n\n\nexport const assertions = {\n\n assertDefined<T>(value: T | null | undefined, message?: string): asserts value is T {\n if (value === null || value === undefined) {\n throw new Error(message || 'Expected value to be defined');\n }\n },\n\n\n assertStatusCode(ctx: BaseContext | { status: number; body?: unknown }, expected: number): void {\n if (ctx.status !== expected) {\n throw new Error(\n `Expected status ${expected} but got ${ctx.status}. Body: ${JSON.stringify(ctx.body)}`,\n );\n }\n },\n\n assertResponseShape(\n body: unknown,\n expectedKeys: string[],\n ): asserts body is Record<string, unknown> {\n if (typeof body !== 'object' || body === null) {\n throw new Error('Expected body to be an object');\n }\n const actualKeys = Object.keys(body);\n const missingKeys = expectedKeys.filter((key) => !actualKeys.includes(key));\n if (missingKeys.length > 0) {\n throw new Error(\n `Missing expected keys in response: ${missingKeys.join(', ')}. Got: ${actualKeys.join(', ')}`,\n );\n }\n },\n\n\n assertExists<T>(value: T | null | undefined, message?: string): asserts value is T {\n if (value === null || value === undefined) {\n throw new Error(message || 'Expected value to exist');\n }\n },\n\n assertType<T>(value: unknown, type: string, message?: string): asserts value is T {\n if (typeof value !== type) {\n throw new Error(message || `Expected value to be of type ${type}, got ${typeof value}`);\n }\n },\n\n validateObjectProperties<T extends Record<string, unknown>>(\n obj: unknown,\n expectedProps: (keyof T)[],\n ): obj is T {\n if (typeof obj !== 'object' || obj === null) {\n return false;\n }\n return expectedProps.every((prop) => prop in obj);\n },\n};\n\nexport interface RouterContext extends BaseContext {\n params: Record<string, string>;\n router?: unknown;\n _matchedRoute?: string;\n _matchedRouteName?: string;\n}\n\n\nexport type RouterMiddleware<TContext = BaseContext> = (\n ctx: TContext,\n next: () => Promise<void>\n) => Promise<void> | void;\n\n\nexport interface RouterLayer<TContext = BaseContext> {\n path: string | RegExp;\n methods: string[];\n stack: RouterMiddleware<TContext>[];\n name?: string | null;\n}\n\n\nexport interface RouterLike<TContext = BaseContext> {\n stack: RouterLayer<TContext>[];\n}\n\nexport async function executeRoute<TContext extends BaseContext = BaseContext>(\n router: { stack: { path: string | RegExp; methods: string[]; stack: unknown[] }[] },\n path: string,\n method: string,\n ctx: TContext,\n): Promise<void> {\n const route = router.stack.find(\n (layer) => layer.path === path && layer.methods.includes(method)\n );\n\n if (!route) {\n throw new Error(`Route not found: ${method} ${path}`);\n }\n\n // Cast context to include router properties\n // We add these properties dynamically, so TypeScript needs to trust us here\n const routerCtx = ctx as TContext & RouterContext;\n if (!routerCtx.params) {\n routerCtx.params = {};\n }\n if (!routerCtx.router) {\n routerCtx.router = router;\n }\n if (!routerCtx._matchedRoute) {\n routerCtx._matchedRoute = path;\n }\n\n // Execute all middlewares in the stack (validation, then handler)\n // Build the middleware chain from right to left\n let index = -1;\n\n const dispatch = async (i: number): Promise<void> => {\n if (i <= index) {\n throw new Error('next() called multiple times');\n }\n index = i;\n\n if (i >= route.stack.length) {\n return;\n }\n\n const middleware = route.stack[i] as (ctx: unknown, next: () => Promise<void>) => Promise<void>;\n return await middleware(routerCtx, () => dispatch(i + 1));\n };\n\n await dispatch(0);\n}\n"],"names":["createMockContext","overrides","ctx","request","body","headers","response","status","undefined","params","query","state","method","path","get","field","toLowerCase","set","value","createMockUser","userUuid","email","firstName","lastName","avatar","role","isSubscriptionActive","createAuthenticatedContext","userOverrides","contextOverrides","user","authorization","mockDatabase","mockModel","methods","findOne","findAll","findByPk","create","update","destroy","count","flushPromises","Promise","resolve","setImmediate","assertions","assertDefined","message","Error","assertStatusCode","expected","JSON","stringify","assertResponseShape","expectedKeys","actualKeys","Object","keys","missingKeys","filter","key","includes","length","join","assertExists","assertType","type","validateObjectProperties","obj","expectedProps","every","prop","executeRoute","router","route","stack","find","layer","routerCtx","_matchedRoute","index","dispatch","i","middleware"],"mappings":"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"}
@@ -54,7 +54,7 @@ export function scrubObject(obj, depth = 0) {
54
54
  }
55
55
  return scrubbedObj;
56
56
  }
57
- const MAX_BODY_SIZE = 10 * 1024;
57
+ const MAX_BODY_SIZE = 100 * 1024; // 100KB - increased from 10KB for full payload visibility
58
58
  export function captureRequestBody(body) {
59
59
  if (!body) {
60
60
  return body;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/lib/utils/SentryUtil.ts"],"sourcesContent":["import * as Sentry from \"@sentry/node\";\nimport type { Context } from \"koa\";\n\nlet sentryInitialized = false;\n\nexport function initializeSentry(): void {\n if (sentryInitialized) {\n return;\n }\n\n const dsn = process.env.SENTRY_DSN;\n const nodeEnv = process.env.NODE_ENV;\n\n if (!dsn || nodeEnv !== \"production\") {\n return;\n }\n\n Sentry.init({\n dsn,\n environment: nodeEnv,\n enabled: true,\n tracesSampleRate: 0,\n });\n\n sentryInitialized = true;\n}\n\nexport function isSentryEnabled(): boolean {\n return sentryInitialized;\n}\n\nconst SENSITIVE_FIELDS = [\n \"password\",\n \"token\",\n \"apikey\",\n \"secret\",\n \"cookie\",\n];\n\nexport function scrubObject(obj: any, depth = 0): any {\n if (depth > 10) {\n return \"[Max Depth]\";\n }\n\n if (obj === null || obj === undefined) {\n return obj;\n }\n\n if (typeof obj !== \"object\") {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => scrubObject(item, depth + 1));\n }\n\n const scrubbedObj: any = {};\n for (const [key, value] of Object.entries(obj)) {\n const keyLower = key.toLowerCase();\n const isSensitive = SENSITIVE_FIELDS.some((field) =>\n keyLower.includes(field),\n );\n\n if (isSensitive) {\n scrubbedObj[key] = \"[REDACTED]\";\n } else if (typeof value === \"object\" && value !== null) {\n scrubbedObj[key] = scrubObject(value, depth + 1);\n } else {\n scrubbedObj[key] = value;\n }\n }\n\n return scrubbedObj;\n}\n\nconst MAX_BODY_SIZE = 10 * 1024;\n\nexport function captureRequestBody(body: any): any {\n if (!body) {\n return body;\n }\n\n const bodyString = JSON.stringify(body);\n if (bodyString.length > MAX_BODY_SIZE) {\n return {\n _truncated: true,\n _originalSize: bodyString.length,\n preview: bodyString.substring(0, MAX_BODY_SIZE),\n };\n }\n\n return scrubObject(body);\n}\n\nexport function extractUserContext(ctx: Context): { id?: string } {\n const user = (ctx.state as any)?.user;\n if (user?.userUuid) {\n return { id: user.userUuid };\n }\n return {};\n}\n\nexport function buildRequestContext(ctx: Context): {\n method: string;\n url: string;\n query: any;\n headers: any;\n data: any;\n ip?: string;\n} {\n return {\n method: ctx.method,\n url: ctx.url,\n query: scrubObject(ctx.query),\n headers: scrubObject(ctx.headers),\n data: captureRequestBody((ctx.request as any).body),\n ip: ctx.ip,\n };\n}\n\nexport function buildResponseContext(ctx: Context): { status_code: number } {\n return {\n status_code: ctx.status,\n };\n}\n\nexport interface ErrorReportOptions {\n operational?: boolean;\n errorType?: string;\n statusCode?: number;\n}\n\nexport function reportErrorToSentry(\n error: Error,\n ctx?: Context,\n options?: ErrorReportOptions,\n): void {\n if (!isSentryEnabled()) {\n return;\n }\n\n Sentry.withScope((scope) => {\n if (ctx) {\n scope.setContext(\"request\", buildRequestContext(ctx));\n scope.setContext(\"response\", buildResponseContext(ctx));\n scope.setUser(extractUserContext(ctx));\n }\n\n if (options?.operational !== undefined) {\n scope.setTag(\"error.operational\", options.operational);\n }\n if (options?.errorType) {\n scope.setTag(\"error.type\", options.errorType);\n }\n if (options?.statusCode) {\n scope.setTag(\"http.status_code\", options.statusCode);\n }\n\n scope.setTag(\"source\", \"middleware\");\n\n Sentry.captureException(error);\n });\n\n (error as any)._sentryReported = true;\n}\n\nexport type SeverityLevel = \"fatal\" | \"error\" | \"warning\" | \"info\" | \"debug\";\n\nexport function reportMessageToSentry(\n message: string,\n level: SeverityLevel,\n context?: Record<string, any>,\n): void {\n if (!isSentryEnabled()) {\n return;\n }\n\n Sentry.withScope((scope) => {\n if (context) {\n for (const [key, value] of Object.entries(context)) {\n if (key === \"logger_name\" || key === \"source\") {\n scope.setTag(key, value);\n } else {\n // Deeply serialize objects and arrays to avoid [Object] and [Array] in Sentry\n const serializedValue =\n typeof value === \"object\" && value !== null\n ? scrubObject(value)\n : value;\n scope.setContext(key, serializedValue);\n }\n }\n }\n\n Sentry.captureMessage(message, level);\n });\n}\n"],"names":["Sentry","sentryInitialized","initializeSentry","dsn","process","env","SENTRY_DSN","nodeEnv","NODE_ENV","init","environment","enabled","tracesSampleRate","isSentryEnabled","SENSITIVE_FIELDS","scrubObject","obj","depth","undefined","Array","isArray","map","item","scrubbedObj","key","value","Object","entries","keyLower","toLowerCase","isSensitive","some","field","includes","MAX_BODY_SIZE","captureRequestBody","body","bodyString","JSON","stringify","length","_truncated","_originalSize","preview","substring","extractUserContext","ctx","user","state","userUuid","id","buildRequestContext","method","url","query","headers","data","request","ip","buildResponseContext","status_code","status","reportErrorToSentry","error","options","withScope","scope","setContext","setUser","operational","setTag","errorType","statusCode","captureException","_sentryReported","reportMessageToSentry","message","level","context","serializedValue","captureMessage"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/lib/utils/SentryUtil.ts"],"sourcesContent":["import * as Sentry from \"@sentry/node\";\nimport type { Context } from \"koa\";\n\nlet sentryInitialized = false;\n\nexport function initializeSentry(): void {\n if (sentryInitialized) {\n return;\n }\n\n const dsn = process.env.SENTRY_DSN;\n const nodeEnv = process.env.NODE_ENV;\n\n if (!dsn || nodeEnv !== \"production\") {\n return;\n }\n\n Sentry.init({\n dsn,\n environment: nodeEnv,\n enabled: true,\n tracesSampleRate: 0,\n });\n\n sentryInitialized = true;\n}\n\nexport function isSentryEnabled(): boolean {\n return sentryInitialized;\n}\n\nconst SENSITIVE_FIELDS = [\n \"password\",\n \"token\",\n \"apikey\",\n \"secret\",\n \"cookie\",\n];\n\nexport function scrubObject(obj: any, depth = 0): any {\n if (depth > 10) {\n return \"[Max Depth]\";\n }\n\n if (obj === null || obj === undefined) {\n return obj;\n }\n\n if (typeof obj !== \"object\") {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => scrubObject(item, depth + 1));\n }\n\n const scrubbedObj: any = {};\n for (const [key, value] of Object.entries(obj)) {\n const keyLower = key.toLowerCase();\n const isSensitive = SENSITIVE_FIELDS.some((field) =>\n keyLower.includes(field),\n );\n\n if (isSensitive) {\n scrubbedObj[key] = \"[REDACTED]\";\n } else if (typeof value === \"object\" && value !== null) {\n scrubbedObj[key] = scrubObject(value, depth + 1);\n } else {\n scrubbedObj[key] = value;\n }\n }\n\n return scrubbedObj;\n}\n\nconst MAX_BODY_SIZE = 100 * 1024; // 100KB - increased from 10KB for full payload visibility\n\nexport function captureRequestBody(body: any): any {\n if (!body) {\n return body;\n }\n\n const bodyString = JSON.stringify(body);\n if (bodyString.length > MAX_BODY_SIZE) {\n return {\n _truncated: true,\n _originalSize: bodyString.length,\n preview: bodyString.substring(0, MAX_BODY_SIZE),\n };\n }\n\n return scrubObject(body);\n}\n\nexport function extractUserContext(ctx: Context): { id?: string } {\n const user = (ctx.state as any)?.user;\n if (user?.userUuid) {\n return { id: user.userUuid };\n }\n return {};\n}\n\nexport function buildRequestContext(ctx: Context): {\n method: string;\n url: string;\n query: any;\n headers: any;\n data: any;\n ip?: string;\n} {\n return {\n method: ctx.method,\n url: ctx.url,\n query: scrubObject(ctx.query),\n headers: scrubObject(ctx.headers),\n data: captureRequestBody((ctx.request as any).body),\n ip: ctx.ip,\n };\n}\n\nexport function buildResponseContext(ctx: Context): { status_code: number } {\n return {\n status_code: ctx.status,\n };\n}\n\nexport interface ErrorReportOptions {\n operational?: boolean;\n errorType?: string;\n statusCode?: number;\n}\n\nexport function reportErrorToSentry(\n error: Error,\n ctx?: Context,\n options?: ErrorReportOptions,\n): void {\n if (!isSentryEnabled()) {\n return;\n }\n\n Sentry.withScope((scope) => {\n if (ctx) {\n scope.setContext(\"request\", buildRequestContext(ctx));\n scope.setContext(\"response\", buildResponseContext(ctx));\n scope.setUser(extractUserContext(ctx));\n }\n\n if (options?.operational !== undefined) {\n scope.setTag(\"error.operational\", options.operational);\n }\n if (options?.errorType) {\n scope.setTag(\"error.type\", options.errorType);\n }\n if (options?.statusCode) {\n scope.setTag(\"http.status_code\", options.statusCode);\n }\n\n scope.setTag(\"source\", \"middleware\");\n\n Sentry.captureException(error);\n });\n\n (error as any)._sentryReported = true;\n}\n\nexport type SeverityLevel = \"fatal\" | \"error\" | \"warning\" | \"info\" | \"debug\";\n\nexport function reportMessageToSentry(\n message: string,\n level: SeverityLevel,\n context?: Record<string, any>,\n): void {\n if (!isSentryEnabled()) {\n return;\n }\n\n Sentry.withScope((scope) => {\n if (context) {\n for (const [key, value] of Object.entries(context)) {\n if (key === \"logger_name\" || key === \"source\") {\n scope.setTag(key, value);\n } else {\n // Deeply serialize objects and arrays to avoid [Object] and [Array] in Sentry\n const serializedValue =\n typeof value === \"object\" && value !== null\n ? scrubObject(value)\n : value;\n scope.setContext(key, serializedValue);\n }\n }\n }\n\n Sentry.captureMessage(message, level);\n });\n}\n"],"names":["Sentry","sentryInitialized","initializeSentry","dsn","process","env","SENTRY_DSN","nodeEnv","NODE_ENV","init","environment","enabled","tracesSampleRate","isSentryEnabled","SENSITIVE_FIELDS","scrubObject","obj","depth","undefined","Array","isArray","map","item","scrubbedObj","key","value","Object","entries","keyLower","toLowerCase","isSensitive","some","field","includes","MAX_BODY_SIZE","captureRequestBody","body","bodyString","JSON","stringify","length","_truncated","_originalSize","preview","substring","extractUserContext","ctx","user","state","userUuid","id","buildRequestContext","method","url","query","headers","data","request","ip","buildResponseContext","status_code","status","reportErrorToSentry","error","options","withScope","scope","setContext","setUser","operational","setTag","errorType","statusCode","captureException","_sentryReported","reportMessageToSentry","message","level","context","serializedValue","captureMessage"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "90dc-core",
3
- "version": "1.16.14",
3
+ "version": "1.16.16",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",