@flusys/nestjs-shared 7.0.2 → 8.0.0-beta.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 (339) hide show
  1. package/classes/api-controller.class.d.ts +4 -4
  2. package/classes/api-service.class.d.ts +7 -7
  3. package/classes/disabled-event-bus.class.d.ts +1 -1
  4. package/classes/domain-event.publisher.d.ts +1 -1
  5. package/classes/event-bus.registry.d.ts +1 -1
  6. package/classes/event-transports/event-transport.registry.d.ts +1 -1
  7. package/classes/event-transports/index.d.ts +2 -2
  8. package/classes/event-transports/kafka-transport.optional.d.ts +1 -1
  9. package/classes/event-transports/memory-transport.d.ts +1 -1
  10. package/classes/event-transports/rabbitmq-transport.optional.d.ts +1 -1
  11. package/classes/hybrid-event-bus.class.d.ts +1 -1
  12. package/classes/index.d.ts +11 -11
  13. package/constants/index.d.ts +2 -2
  14. package/constants/permissions.d.ts +12 -0
  15. package/decorators/api-response.decorator.d.ts +1 -1
  16. package/decorators/current-user.decorator.d.ts +1 -1
  17. package/decorators/index.d.ts +6 -6
  18. package/decorators/require-permission.decorator.d.ts +1 -1
  19. package/dtos/filter-and-pagination.dto.d.ts +1 -1
  20. package/dtos/index.d.ts +6 -6
  21. package/entities/index.d.ts +3 -3
  22. package/enums/index.d.ts +3 -3
  23. package/exceptions/index.d.ts +2 -2
  24. package/fesm/470.js +2713 -0
  25. package/fesm/509.js +793 -0
  26. package/fesm/667.js +606 -0
  27. package/fesm/67.js +808 -0
  28. package/fesm/720.js +914 -0
  29. package/{cjs/classes/event-transports/rabbitmq-transport.optional.js → fesm/chunks/123.js} +78 -55
  30. package/fesm/{classes/event-transports/kafka-transport.optional.js → chunks/37.js} +74 -41
  31. package/fesm/classes/index.js +62 -12
  32. package/fesm/constants/index.js +445 -17
  33. package/fesm/decorators/index.js +341 -6
  34. package/fesm/dtos/index.js +23 -6
  35. package/fesm/entities/index.js +336 -3
  36. package/fesm/enums/index.js +57 -3
  37. package/fesm/exceptions/index.js +280 -2
  38. package/fesm/guards/index.js +1003 -3
  39. package/fesm/index.js +1524 -14
  40. package/fesm/interceptors/index.js +924 -5
  41. package/fesm/interfaces/index.js +57 -11
  42. package/fesm/middlewares/index.js +33 -1
  43. package/fesm/modules/index.js +432 -9
  44. package/fesm/runtime.js +134 -0
  45. package/fesm/utils/index.js +1045 -8
  46. package/filters/global-exception.filter.d.ts +1 -1
  47. package/filters/index.d.ts +1 -1
  48. package/guards/index.d.ts +3 -3
  49. package/guards/jwt-auth.guard.d.ts +1 -1
  50. package/guards/optional-jwt-auth.guard.d.ts +1 -1
  51. package/guards/permission.guard.d.ts +2 -2
  52. package/index.d.ts +14 -14
  53. package/interceptors/delete-empty-id-from-body.interceptor.d.ts +1 -1
  54. package/interceptors/idempotency.interceptor.d.ts +2 -2
  55. package/interceptors/index.d.ts +5 -5
  56. package/interceptors/response-meta.interceptor.d.ts +1 -1
  57. package/interceptors/set-user-field-on-body.interceptor.d.ts +1 -1
  58. package/interceptors/slug.interceptor.d.ts +2 -2
  59. package/interfaces/ai-assistant-adapter.interface.d.ts +1 -1
  60. package/interfaces/api.interface.d.ts +2 -2
  61. package/interfaces/datasource.interface.d.ts +1 -1
  62. package/interfaces/event-manager-adapter.interface.d.ts +2 -2
  63. package/interfaces/index.d.ts +11 -11
  64. package/interfaces/module-config.interface.d.ts +1 -1
  65. package/interfaces/notification-adapter.interface.d.ts +1 -1
  66. package/middlewares/index.d.ts +1 -1
  67. package/middlewares/logger.middleware.d.ts +2 -2
  68. package/modules/cache/cache.module.d.ts +1 -1
  69. package/modules/datasource/index.d.ts +1 -1
  70. package/modules/datasource/multi-tenant-datasource.service.d.ts +4 -4
  71. package/modules/event-bus/event-bus.explorer.d.ts +2 -2
  72. package/modules/event-bus/event-bus.module.d.ts +2 -2
  73. package/modules/event-bus/module-events.provider.d.ts +1 -1
  74. package/modules/index.d.ts +9 -9
  75. package/modules/shared-permission-cache/shared-permission-cache.service.d.ts +3 -3
  76. package/modules/utils/utils.service.d.ts +1 -1
  77. package/package.json +30 -44
  78. package/utils/index.d.ts +8 -8
  79. package/utils/permission-cache-key.util.d.ts +1 -1
  80. package/utils/query-helpers.util.d.ts +2 -2
  81. package/utils/request.util.d.ts +1 -1
  82. package/cjs/classes/api-controller.class.js +0 -728
  83. package/cjs/classes/api-controller.class.spec.js +0 -684
  84. package/cjs/classes/api-service.class.js +0 -631
  85. package/cjs/classes/api-service.class.spec.js +0 -1137
  86. package/cjs/classes/disabled-event-bus.class.js +0 -15
  87. package/cjs/classes/disabled-event-bus.class.spec.js +0 -40
  88. package/cjs/classes/domain-event.publisher.js +0 -76
  89. package/cjs/classes/domain-event.publisher.spec.js +0 -234
  90. package/cjs/classes/event-bus.registry.js +0 -68
  91. package/cjs/classes/event-bus.registry.spec.js +0 -141
  92. package/cjs/classes/event-transports/event-transport.registry.js +0 -41
  93. package/cjs/classes/event-transports/event-transport.registry.spec.js +0 -31
  94. package/cjs/classes/event-transports/index.js +0 -23
  95. package/cjs/classes/event-transports/kafka-transport.optional.js +0 -151
  96. package/cjs/classes/event-transports/kafka-transport.optional.spec.js +0 -198
  97. package/cjs/classes/event-transports/memory-transport.js +0 -53
  98. package/cjs/classes/event-transports/memory-transport.spec.js +0 -57
  99. package/cjs/classes/event-transports/rabbitmq-transport.optional.spec.js +0 -255
  100. package/cjs/classes/handle-custome-db.js +0 -37
  101. package/cjs/classes/handle-custome-db.spec.js +0 -82
  102. package/cjs/classes/hybrid-cache.class.js +0 -96
  103. package/cjs/classes/hybrid-cache.class.spec.js +0 -168
  104. package/cjs/classes/hybrid-event-bus.class.js +0 -281
  105. package/cjs/classes/hybrid-event-bus.class.spec.js +0 -218
  106. package/cjs/classes/index.js +0 -28
  107. package/cjs/classes/winston.logger.class.js +0 -274
  108. package/cjs/classes/winston.logger.class.spec.js +0 -330
  109. package/cjs/constants/index.js +0 -88
  110. package/cjs/constants/message-keys.js +0 -68
  111. package/cjs/constants/permissions.js +0 -297
  112. package/cjs/decorators/api-response.decorator.js +0 -52
  113. package/cjs/decorators/api-response.decorator.spec.js +0 -126
  114. package/cjs/decorators/current-user.decorator.js +0 -16
  115. package/cjs/decorators/current-user.decorator.spec.js +0 -74
  116. package/cjs/decorators/index.js +0 -23
  117. package/cjs/decorators/log-action.decorator.js +0 -149
  118. package/cjs/decorators/log-action.decorator.spec.js +0 -353
  119. package/cjs/decorators/on-domain-event.decorator.js +0 -13
  120. package/cjs/decorators/on-domain-event.decorator.spec.js +0 -50
  121. package/cjs/decorators/public.decorator.js +0 -13
  122. package/cjs/decorators/public.decorator.spec.js +0 -50
  123. package/cjs/decorators/require-permission.decorator.js +0 -32
  124. package/cjs/decorators/require-permission.decorator.spec.js +0 -147
  125. package/cjs/dtos/delete.dto.js +0 -92
  126. package/cjs/dtos/filter-and-pagination.dto.js +0 -164
  127. package/cjs/dtos/get-by-ids.dto.js +0 -65
  128. package/cjs/dtos/identity-response.dto.js +0 -108
  129. package/cjs/dtos/index.js +0 -23
  130. package/cjs/dtos/pagination.dto.js +0 -67
  131. package/cjs/dtos/response-payload.dto.js +0 -369
  132. package/cjs/entities/identity.js +0 -100
  133. package/cjs/entities/index.js +0 -20
  134. package/cjs/entities/raw-type.js +0 -4
  135. package/cjs/entities/user-root.js +0 -189
  136. package/cjs/enums/index.js +0 -20
  137. package/cjs/enums/notification-type.enum.js +0 -17
  138. package/cjs/enums/participant-status.enum.js +0 -17
  139. package/cjs/enums/recurrence-type.enum.js +0 -18
  140. package/cjs/exceptions/base-app.exception.js +0 -151
  141. package/cjs/exceptions/base-app.exception.spec.js +0 -157
  142. package/cjs/exceptions/index.js +0 -19
  143. package/cjs/exceptions/permission.exception.js +0 -56
  144. package/cjs/exceptions/permission.exception.spec.js +0 -82
  145. package/cjs/filters/global-exception.filter.js +0 -279
  146. package/cjs/filters/global-exception.filter.spec.js +0 -440
  147. package/cjs/filters/index.js +0 -18
  148. package/cjs/guards/index.js +0 -20
  149. package/cjs/guards/jwt-auth.guard.js +0 -75
  150. package/cjs/guards/jwt-auth.guard.spec.js +0 -75
  151. package/cjs/guards/optional-jwt-auth.guard.js +0 -67
  152. package/cjs/guards/optional-jwt-auth.guard.spec.js +0 -55
  153. package/cjs/guards/permission.guard.js +0 -179
  154. package/cjs/guards/permission.guard.spec.js +0 -373
  155. package/cjs/index.js +0 -31
  156. package/cjs/interceptors/delete-empty-id-from-body.interceptor.js +0 -40
  157. package/cjs/interceptors/delete-empty-id-from-body.interceptor.spec.js +0 -107
  158. package/cjs/interceptors/idempotency.interceptor.js +0 -96
  159. package/cjs/interceptors/idempotency.interceptor.spec.js +0 -116
  160. package/cjs/interceptors/index.js +0 -22
  161. package/cjs/interceptors/response-meta.interceptor.js +0 -47
  162. package/cjs/interceptors/response-meta.interceptor.spec.js +0 -89
  163. package/cjs/interceptors/set-user-field-on-body.interceptor.js +0 -60
  164. package/cjs/interceptors/set-user-field-on-body.interceptor.spec.js +0 -128
  165. package/cjs/interceptors/slug.interceptor.js +0 -75
  166. package/cjs/interceptors/slug.interceptor.spec.js +0 -110
  167. package/cjs/interfaces/ai-assistant-adapter.interface.js +0 -24
  168. package/cjs/interfaces/api.interface.js +0 -4
  169. package/cjs/interfaces/datasource.interface.js +0 -4
  170. package/cjs/interfaces/event-bus.interface.js +0 -4
  171. package/cjs/interfaces/event-manager-adapter.interface.js +0 -11
  172. package/cjs/interfaces/identity.interface.js +0 -4
  173. package/cjs/interfaces/index.js +0 -28
  174. package/cjs/interfaces/logged-user-info.interface.js +0 -6
  175. package/cjs/interfaces/module-config.interface.js +0 -4
  176. package/cjs/interfaces/notification-adapter.interface.js +0 -11
  177. package/cjs/interfaces/permission-sync-adapter.interface.js +0 -11
  178. package/cjs/interfaces/permission.interface.js +0 -4
  179. package/cjs/middlewares/index.js +0 -18
  180. package/cjs/middlewares/logger.middleware.js +0 -264
  181. package/cjs/middlewares/logger.middleware.spec.js +0 -462
  182. package/cjs/modules/cache/cache.module.js +0 -39
  183. package/cjs/modules/cache/cache.module.spec.js +0 -48
  184. package/cjs/modules/datasource/index.js +0 -18
  185. package/cjs/modules/datasource/multi-tenant-datasource.service.js +0 -222
  186. package/cjs/modules/datasource/multi-tenant-datasource.service.spec.js +0 -381
  187. package/cjs/modules/event-bus/event-bus.explorer.js +0 -124
  188. package/cjs/modules/event-bus/event-bus.explorer.spec.js +0 -189
  189. package/cjs/modules/event-bus/event-bus.integration.spec.js +0 -253
  190. package/cjs/modules/event-bus/event-bus.module.js +0 -94
  191. package/cjs/modules/event-bus/event-bus.module.spec.js +0 -149
  192. package/cjs/modules/event-bus/module-events.provider.js +0 -39
  193. package/cjs/modules/event-bus/module-events.provider.spec.js +0 -56
  194. package/cjs/modules/index.js +0 -26
  195. package/cjs/modules/shared-permission-cache/shared-permission-cache.module.js +0 -32
  196. package/cjs/modules/shared-permission-cache/shared-permission-cache.service.js +0 -101
  197. package/cjs/modules/shared-permission-cache/shared-permission-cache.service.spec.js +0 -165
  198. package/cjs/modules/utils/utils.module.js +0 -32
  199. package/cjs/modules/utils/utils.service.js +0 -76
  200. package/cjs/modules/utils/utils.service.spec.js +0 -169
  201. package/cjs/utils/date-time.util.js +0 -94
  202. package/cjs/utils/date-time.util.spec.js +0 -84
  203. package/cjs/utils/event-pattern.util.js +0 -103
  204. package/cjs/utils/event-pattern.util.spec.js +0 -251
  205. package/cjs/utils/html-sanitizer.util.js +0 -64
  206. package/cjs/utils/html-sanitizer.util.spec.js +0 -76
  207. package/cjs/utils/index.js +0 -25
  208. package/cjs/utils/optional-module.util.js +0 -35
  209. package/cjs/utils/optional-module.util.spec.js +0 -14
  210. package/cjs/utils/permission-cache-key.util.js +0 -31
  211. package/cjs/utils/permission-cache-key.util.spec.js +0 -88
  212. package/cjs/utils/query-helpers.util.js +0 -60
  213. package/cjs/utils/query-helpers.util.spec.js +0 -209
  214. package/cjs/utils/request.util.js +0 -96
  215. package/cjs/utils/request.util.spec.js +0 -249
  216. package/cjs/utils/string.util.js +0 -63
  217. package/cjs/utils/string.util.spec.js +0 -63
  218. package/fesm/classes/api-controller.class.js +0 -718
  219. package/fesm/classes/api-controller.class.spec.js +0 -680
  220. package/fesm/classes/api-service.class.js +0 -621
  221. package/fesm/classes/api-service.class.spec.js +0 -1133
  222. package/fesm/classes/disabled-event-bus.class.js +0 -11
  223. package/fesm/classes/disabled-event-bus.class.spec.js +0 -36
  224. package/fesm/classes/domain-event.publisher.js +0 -63
  225. package/fesm/classes/domain-event.publisher.spec.js +0 -230
  226. package/fesm/classes/event-bus.registry.js +0 -64
  227. package/fesm/classes/event-bus.registry.spec.js +0 -137
  228. package/fesm/classes/event-transports/event-transport.registry.js +0 -35
  229. package/fesm/classes/event-transports/event-transport.registry.spec.js +0 -27
  230. package/fesm/classes/event-transports/index.js +0 -6
  231. package/fesm/classes/event-transports/kafka-transport.optional.spec.js +0 -194
  232. package/fesm/classes/event-transports/memory-transport.js +0 -49
  233. package/fesm/classes/event-transports/memory-transport.spec.js +0 -53
  234. package/fesm/classes/event-transports/rabbitmq-transport.optional.js +0 -174
  235. package/fesm/classes/event-transports/rabbitmq-transport.optional.spec.js +0 -251
  236. package/fesm/classes/handle-custome-db.js +0 -19
  237. package/fesm/classes/handle-custome-db.spec.js +0 -78
  238. package/fesm/classes/hybrid-cache.class.js +0 -81
  239. package/fesm/classes/hybrid-cache.class.spec.js +0 -164
  240. package/fesm/classes/hybrid-event-bus.class.js +0 -237
  241. package/fesm/classes/hybrid-event-bus.class.spec.js +0 -214
  242. package/fesm/classes/winston.logger.class.js +0 -228
  243. package/fesm/classes/winston.logger.class.spec.js +0 -327
  244. package/fesm/constants/message-keys.js +0 -49
  245. package/fesm/constants/permissions.js +0 -208
  246. package/fesm/decorators/api-response.decorator.js +0 -42
  247. package/fesm/decorators/api-response.decorator.spec.js +0 -122
  248. package/fesm/decorators/current-user.decorator.js +0 -18
  249. package/fesm/decorators/current-user.decorator.spec.js +0 -73
  250. package/fesm/decorators/log-action.decorator.js +0 -139
  251. package/fesm/decorators/log-action.decorator.spec.js +0 -349
  252. package/fesm/decorators/on-domain-event.decorator.js +0 -10
  253. package/fesm/decorators/on-domain-event.decorator.spec.js +0 -46
  254. package/fesm/decorators/public.decorator.js +0 -20
  255. package/fesm/decorators/public.decorator.spec.js +0 -46
  256. package/fesm/decorators/require-permission.decorator.js +0 -27
  257. package/fesm/decorators/require-permission.decorator.spec.js +0 -143
  258. package/fesm/dtos/delete.dto.js +0 -82
  259. package/fesm/dtos/filter-and-pagination.dto.js +0 -148
  260. package/fesm/dtos/get-by-ids.dto.js +0 -55
  261. package/fesm/dtos/identity-response.dto.js +0 -98
  262. package/fesm/dtos/pagination.dto.js +0 -57
  263. package/fesm/dtos/response-payload.dto.js +0 -336
  264. package/fesm/entities/identity.js +0 -90
  265. package/fesm/entities/raw-type.js +0 -1
  266. package/fesm/entities/user-root.js +0 -179
  267. package/fesm/enums/notification-type.enum.js +0 -7
  268. package/fesm/enums/participant-status.enum.js +0 -7
  269. package/fesm/enums/recurrence-type.enum.js +0 -8
  270. package/fesm/exceptions/base-app.exception.js +0 -115
  271. package/fesm/exceptions/base-app.exception.spec.js +0 -153
  272. package/fesm/exceptions/permission.exception.js +0 -35
  273. package/fesm/exceptions/permission.exception.spec.js +0 -78
  274. package/fesm/filters/global-exception.filter.js +0 -269
  275. package/fesm/filters/global-exception.filter.spec.js +0 -436
  276. package/fesm/filters/index.js +0 -1
  277. package/fesm/guards/jwt-auth.guard.js +0 -65
  278. package/fesm/guards/jwt-auth.guard.spec.js +0 -71
  279. package/fesm/guards/optional-jwt-auth.guard.js +0 -57
  280. package/fesm/guards/optional-jwt-auth.guard.spec.js +0 -51
  281. package/fesm/guards/permission.guard.js +0 -169
  282. package/fesm/guards/permission.guard.spec.js +0 -369
  283. package/fesm/interceptors/delete-empty-id-from-body.interceptor.js +0 -30
  284. package/fesm/interceptors/delete-empty-id-from-body.interceptor.spec.js +0 -103
  285. package/fesm/interceptors/idempotency.interceptor.js +0 -86
  286. package/fesm/interceptors/idempotency.interceptor.spec.js +0 -112
  287. package/fesm/interceptors/response-meta.interceptor.js +0 -37
  288. package/fesm/interceptors/response-meta.interceptor.spec.js +0 -85
  289. package/fesm/interceptors/set-user-field-on-body.interceptor.js +0 -39
  290. package/fesm/interceptors/set-user-field-on-body.interceptor.spec.js +0 -124
  291. package/fesm/interceptors/slug.interceptor.js +0 -65
  292. package/fesm/interceptors/slug.interceptor.spec.js +0 -106
  293. package/fesm/interfaces/ai-assistant-adapter.interface.js +0 -3
  294. package/fesm/interfaces/api.interface.js +0 -1
  295. package/fesm/interfaces/datasource.interface.js +0 -1
  296. package/fesm/interfaces/event-bus.interface.js +0 -1
  297. package/fesm/interfaces/event-manager-adapter.interface.js +0 -1
  298. package/fesm/interfaces/identity.interface.js +0 -1
  299. package/fesm/interfaces/logged-user-info.interface.js +0 -3
  300. package/fesm/interfaces/module-config.interface.js +0 -5
  301. package/fesm/interfaces/notification-adapter.interface.js +0 -1
  302. package/fesm/interfaces/permission-sync-adapter.interface.js +0 -1
  303. package/fesm/interfaces/permission.interface.js +0 -1
  304. package/fesm/middlewares/logger.middleware.js +0 -235
  305. package/fesm/middlewares/logger.middleware.spec.js +0 -459
  306. package/fesm/modules/cache/cache.module.js +0 -29
  307. package/fesm/modules/cache/cache.module.spec.js +0 -44
  308. package/fesm/modules/datasource/index.js +0 -1
  309. package/fesm/modules/datasource/multi-tenant-datasource.service.js +0 -212
  310. package/fesm/modules/datasource/multi-tenant-datasource.service.spec.js +0 -377
  311. package/fesm/modules/event-bus/event-bus.explorer.js +0 -114
  312. package/fesm/modules/event-bus/event-bus.explorer.spec.js +0 -185
  313. package/fesm/modules/event-bus/event-bus.integration.spec.js +0 -249
  314. package/fesm/modules/event-bus/event-bus.module.js +0 -84
  315. package/fesm/modules/event-bus/event-bus.module.spec.js +0 -145
  316. package/fesm/modules/event-bus/module-events.provider.js +0 -26
  317. package/fesm/modules/event-bus/module-events.provider.spec.js +0 -52
  318. package/fesm/modules/shared-permission-cache/shared-permission-cache.module.js +0 -22
  319. package/fesm/modules/shared-permission-cache/shared-permission-cache.service.js +0 -91
  320. package/fesm/modules/shared-permission-cache/shared-permission-cache.service.spec.js +0 -161
  321. package/fesm/modules/utils/utils.module.js +0 -22
  322. package/fesm/modules/utils/utils.service.js +0 -66
  323. package/fesm/modules/utils/utils.service.spec.js +0 -165
  324. package/fesm/utils/date-time.util.js +0 -70
  325. package/fesm/utils/date-time.util.spec.js +0 -80
  326. package/fesm/utils/event-pattern.util.js +0 -91
  327. package/fesm/utils/event-pattern.util.spec.js +0 -247
  328. package/fesm/utils/html-sanitizer.util.js +0 -69
  329. package/fesm/utils/html-sanitizer.util.spec.js +0 -72
  330. package/fesm/utils/optional-module.util.js +0 -25
  331. package/fesm/utils/optional-module.util.spec.js +0 -10
  332. package/fesm/utils/permission-cache-key.util.js +0 -10
  333. package/fesm/utils/permission-cache-key.util.spec.js +0 -84
  334. package/fesm/utils/query-helpers.util.js +0 -85
  335. package/fesm/utils/query-helpers.util.spec.js +0 -205
  336. package/fesm/utils/request.util.js +0 -81
  337. package/fesm/utils/request.util.spec.js +0 -245
  338. package/fesm/utils/string.util.js +0 -71
  339. package/fesm/utils/string.util.spec.js +0 -59
@@ -1,165 +0,0 @@
1
- import { UtilsService } from './utils.service';
2
- describe('UtilsService', ()=>{
3
- let service;
4
- let mockCache;
5
- beforeEach(()=>{
6
- service = new UtilsService();
7
- mockCache = {
8
- get: jest.fn(),
9
- set: jest.fn(),
10
- del: jest.fn()
11
- };
12
- });
13
- describe('getCacheKey', ()=>{
14
- it('should build an "all" key from the entity name and params when no id is given', ()=>{
15
- const key = service.getCacheKey('product', {
16
- page: 1
17
- });
18
- expect(key).toBe('entity_product_all_{"page":1}');
19
- });
20
- it('should build a per-id key with a select suffix when params are given', ()=>{
21
- const key = service.getCacheKey('product', {
22
- fields: [
23
- 'name'
24
- ]
25
- }, 'prod-1');
26
- expect(key).toBe('entity_product_id_prod-1_select_{"fields":["name"]}');
27
- });
28
- it('should build a per-id key without a select suffix when params are falsy', ()=>{
29
- const key = service.getCacheKey('product', null, 'prod-1');
30
- expect(key).toBe('entity_product_id_prod-1');
31
- });
32
- it('should prefix the key with the tenant id when provided', ()=>{
33
- const key = service.getCacheKey('product', {
34
- page: 1
35
- }, undefined, 'tenant-a');
36
- expect(key).toBe('tenant_tenant-a_entity_product_all_{"page":1}');
37
- });
38
- it('should prefix a per-id key with the tenant id too', ()=>{
39
- const key = service.getCacheKey('product', undefined, 'prod-1', 'tenant-a');
40
- expect(key).toBe('tenant_tenant-a_entity_product_id_prod-1');
41
- });
42
- });
43
- describe('trackCacheKey', ()=>{
44
- it('should create a new tracking list when none exists yet', async ()=>{
45
- mockCache.get.mockResolvedValue(undefined);
46
- await service.trackCacheKey('cache-key-1', 'product', mockCache);
47
- expect(mockCache.set).toHaveBeenCalledWith('entity_product_keys', [
48
- 'cache-key-1'
49
- ]);
50
- });
51
- it('should append to an existing tracking list without duplicating entries', async ()=>{
52
- mockCache.get.mockResolvedValue([
53
- 'cache-key-1'
54
- ]);
55
- await service.trackCacheKey('cache-key-1', 'product', mockCache);
56
- expect(mockCache.set).toHaveBeenCalledWith('entity_product_keys', [
57
- 'cache-key-1'
58
- ]);
59
- });
60
- it('should append a new key alongside existing ones', async ()=>{
61
- mockCache.get.mockResolvedValue([
62
- 'cache-key-1'
63
- ]);
64
- await service.trackCacheKey('cache-key-2', 'product', mockCache);
65
- expect(mockCache.set).toHaveBeenCalledWith('entity_product_keys', [
66
- 'cache-key-1',
67
- 'cache-key-2'
68
- ]);
69
- });
70
- it('should scope the tracking key by entity id and tenant', async ()=>{
71
- mockCache.get.mockResolvedValue(undefined);
72
- await service.trackCacheKey('cache-key-1', 'product', mockCache, 'prod-1', 'tenant-a');
73
- expect(mockCache.get).toHaveBeenCalledWith('tenant_tenant-a_entity_product_id_prod-1_keys');
74
- expect(mockCache.set).toHaveBeenCalledWith('tenant_tenant-a_entity_product_id_prod-1_keys', [
75
- 'cache-key-1'
76
- ]);
77
- });
78
- it('should swallow cache read errors without throwing', async ()=>{
79
- mockCache.get.mockRejectedValue(new Error('cache down'));
80
- await expect(service.trackCacheKey('k', 'product', mockCache)).resolves.toBeUndefined();
81
- expect(mockCache.set).not.toHaveBeenCalled();
82
- });
83
- it('should swallow cache write errors without throwing', async ()=>{
84
- mockCache.get.mockResolvedValue([]);
85
- mockCache.set.mockRejectedValue(new Error('cache down'));
86
- await expect(service.trackCacheKey('k', 'product', mockCache)).resolves.toBeUndefined();
87
- });
88
- });
89
- describe('clearCache', ()=>{
90
- it('should delete every tracked key plus the tracking key itself', async ()=>{
91
- mockCache.get.mockResolvedValue([
92
- 'k1',
93
- 'k2'
94
- ]);
95
- await service.clearCache('product', mockCache);
96
- expect(mockCache.del).toHaveBeenCalledWith('k1');
97
- expect(mockCache.del).toHaveBeenCalledWith('k2');
98
- expect(mockCache.del).toHaveBeenCalledWith('entity_product_keys');
99
- expect(mockCache.del).toHaveBeenCalledTimes(3);
100
- });
101
- it('should only delete the tracking key when no keys were tracked', async ()=>{
102
- mockCache.get.mockResolvedValue(undefined);
103
- await service.clearCache('product', mockCache);
104
- expect(mockCache.del).toHaveBeenCalledTimes(1);
105
- expect(mockCache.del).toHaveBeenCalledWith('entity_product_keys');
106
- });
107
- it('should continue deleting remaining keys even if one deletion rejects', async ()=>{
108
- mockCache.get.mockResolvedValue([
109
- 'k1',
110
- 'k2'
111
- ]);
112
- mockCache.del.mockImplementation((key)=>key === 'k1' ? Promise.reject(new Error('fail')) : Promise.resolve());
113
- await service.clearCache('product', mockCache);
114
- expect(mockCache.del).toHaveBeenCalledWith('k2');
115
- expect(mockCache.del).toHaveBeenCalledWith('entity_product_keys');
116
- });
117
- it('should scope deletion by entity id and tenant', async ()=>{
118
- mockCache.get.mockResolvedValue([
119
- 'k1'
120
- ]);
121
- await service.clearCache('product', mockCache, 'prod-1', 'tenant-a');
122
- expect(mockCache.get).toHaveBeenCalledWith('tenant_tenant-a_entity_product_id_prod-1_keys');
123
- });
124
- it('should swallow errors from the initial cache read', async ()=>{
125
- mockCache.get.mockRejectedValue(new Error('cache down'));
126
- await expect(service.clearCache('product', mockCache)).resolves.toBeUndefined();
127
- expect(mockCache.del).not.toHaveBeenCalled();
128
- });
129
- });
130
- describe('transformToSlug', ()=>{
131
- it('should lowercase and dash-separate a normal string', ()=>{
132
- expect(service.transformToSlug('Hello World')).toBe('hello-world');
133
- });
134
- it('should collapse runs of non-alphanumeric characters into a single dash', ()=>{
135
- expect(service.transformToSlug('Hello World!!!')).toBe('hello-world-');
136
- });
137
- it('should trim leading/trailing whitespace before slugging', ()=>{
138
- expect(service.transformToSlug(' Hello World ')).toBe('hello-world');
139
- });
140
- it('should append a random numeric salt when requested', ()=>{
141
- const randomSpy = jest.spyOn(service, 'getRandomInt').mockReturnValue(42);
142
- expect(service.transformToSlug('Hello World', true)).toBe('hello-world-42');
143
- randomSpy.mockRestore();
144
- });
145
- it('should handle an empty string', ()=>{
146
- expect(service.transformToSlug('')).toBe('');
147
- });
148
- it('should handle strings that are entirely non-alphanumeric', ()=>{
149
- expect(service.transformToSlug('!!!')).toBe('-');
150
- });
151
- });
152
- describe('getRandomInt', ()=>{
153
- it('should return the exact bound when min equals max', ()=>{
154
- expect(service.getRandomInt(5, 5)).toBe(5);
155
- });
156
- it('should stay within an inclusive [min, max] range across many samples', ()=>{
157
- for(let i = 0; i < 200; i++){
158
- const value = service.getRandomInt(1, 10);
159
- expect(value).toBeGreaterThanOrEqual(1);
160
- expect(value).toBeLessThanOrEqual(10);
161
- expect(Number.isInteger(value)).toBe(true);
162
- }
163
- });
164
- });
165
- });
@@ -1,70 +0,0 @@
1
- function getOffsetMinutes(utcDate, timezone) {
2
- const extract = (tz)=>{
3
- const parts = new Intl.DateTimeFormat('en-US', {
4
- timeZone: tz,
5
- year: 'numeric',
6
- month: '2-digit',
7
- day: '2-digit',
8
- hour: '2-digit',
9
- minute: '2-digit',
10
- second: '2-digit',
11
- hour12: false
12
- }).formatToParts(utcDate);
13
- const p = Object.fromEntries(parts.filter((x)=>x.type !== 'literal').map((x)=>[
14
- x.type,
15
- parseInt(x.value)
16
- ]));
17
- return Date.UTC(p['year'], p['month'] - 1, p['day'], p['hour'], p['minute'], p['second']);
18
- };
19
- return (extract(timezone) - extract('UTC')) / 60_000;
20
- }
21
- export function localToUtc(dateStr, timeStr, timezone) {
22
- const [year, month, day] = dateStr.split('-').map(Number);
23
- const [hours, minutes] = timeStr.split(':').map(Number);
24
- const approx = new Date(Date.UTC(year, month - 1, day, hours, minutes, 0));
25
- const offset = getOffsetMinutes(approx, timezone);
26
- const utcDate = new Date(approx.getTime() - offset * 60_000);
27
- // DST boundary guard: re-check offset after adjustment
28
- const finalOffset = getOffsetMinutes(utcDate, timezone);
29
- return finalOffset !== offset ? new Date(approx.getTime() - finalOffset * 60_000) : utcDate;
30
- }
31
- export function utcToLocal(utcDate, timezone) {
32
- const d = typeof utcDate === 'string' ? new Date(utcDate) : utcDate;
33
- const parts = new Intl.DateTimeFormat('en-CA', {
34
- timeZone: timezone,
35
- year: 'numeric',
36
- month: '2-digit',
37
- day: '2-digit',
38
- hour: '2-digit',
39
- minute: '2-digit',
40
- hour12: false
41
- }).formatToParts(d);
42
- const p = Object.fromEntries(parts.filter((x)=>x.type !== 'literal').map((x)=>[
43
- x.type,
44
- x.value
45
- ]));
46
- // en-CA formats midnight hour as '24' — normalize to '00'
47
- const hour = p['hour'] === '24' ? '00' : p['hour'];
48
- return {
49
- date: `${p['year']}-${p['month']}-${p['day']}`,
50
- time: `${hour}:${p['minute']}`,
51
- display: new Intl.DateTimeFormat('en-US', {
52
- timeZone: timezone,
53
- dateStyle: 'medium',
54
- timeStyle: 'short'
55
- }).format(d)
56
- };
57
- }
58
- export function formatInTimezone(utcDate, timezone, options = {
59
- dateStyle: 'medium',
60
- timeStyle: 'short'
61
- }) {
62
- const d = typeof utcDate === 'string' ? new Date(utcDate) : utcDate;
63
- return new Intl.DateTimeFormat('en-US', {
64
- ...options,
65
- timeZone: timezone
66
- }).format(d);
67
- }
68
- export function getTodayInTimezone(timezone) {
69
- return utcToLocal(new Date(), timezone).date;
70
- }
@@ -1,80 +0,0 @@
1
- import { formatInTimezone, getTodayInTimezone, localToUtc, utcToLocal } from './date-time.util';
2
- describe('date-time.util', ()=>{
3
- describe('localToUtc', ()=>{
4
- it('should convert a local date/time in a fixed-offset timezone to UTC', ()=>{
5
- // Asia/Dhaka is UTC+6, no DST
6
- const result = localToUtc('2026-01-15', '10:00', 'Asia/Dhaka');
7
- expect(result.toISOString()).toBe('2026-01-15T04:00:00.000Z');
8
- });
9
- it('should convert local time in UTC timezone unchanged', ()=>{
10
- const result = localToUtc('2026-06-01', '12:30', 'UTC');
11
- expect(result.toISOString()).toBe('2026-06-01T12:30:00.000Z');
12
- });
13
- it('should handle a negative UTC offset timezone (America/New_York in winter, no DST)', ()=>{
14
- // America/New_York is UTC-5 in January (standard time, no DST)
15
- const result = localToUtc('2026-01-15', '09:00', 'America/New_York');
16
- expect(result.toISOString()).toBe('2026-01-15T14:00:00.000Z');
17
- });
18
- it('should account for DST when converting a summer date in America/New_York (UTC-4)', ()=>{
19
- const result = localToUtc('2026-07-15', '09:00', 'America/New_York');
20
- expect(result.toISOString()).toBe('2026-07-15T13:00:00.000Z');
21
- });
22
- });
23
- describe('utcToLocal', ()=>{
24
- it('should convert a UTC Date to local date/time/display parts', ()=>{
25
- const result = utcToLocal(new Date('2026-01-15T04:00:00.000Z'), 'Asia/Dhaka');
26
- expect(result.date).toBe('2026-01-15');
27
- expect(result.time).toBe('10:00');
28
- expect(result.display).toEqual(expect.any(String));
29
- });
30
- it('should accept a UTC date string as input', ()=>{
31
- const result = utcToLocal('2026-01-15T04:00:00.000Z', 'Asia/Dhaka');
32
- expect(result.date).toBe('2026-01-15');
33
- expect(result.time).toBe('10:00');
34
- });
35
- it('should normalize midnight (en-CA "24") to "00"', ()=>{
36
- // 00:00 Dhaka time == 18:00 UTC the previous day
37
- const result = utcToLocal('2026-01-14T18:00:00.000Z', 'Asia/Dhaka');
38
- expect(result.date).toBe('2026-01-15');
39
- expect(result.time).toBe('00:00');
40
- });
41
- });
42
- describe('formatInTimezone', ()=>{
43
- it('should format a date in the given timezone with default options', ()=>{
44
- const result = formatInTimezone('2026-01-15T04:00:00.000Z', 'Asia/Dhaka');
45
- expect(typeof result).toBe('string');
46
- expect(result.length).toBeGreaterThan(0);
47
- });
48
- it('should respect custom Intl.DateTimeFormatOptions', ()=>{
49
- const result = formatInTimezone('2026-01-15T04:00:00.000Z', 'UTC', {
50
- year: 'numeric'
51
- });
52
- expect(result).toBe('2026');
53
- });
54
- it('should accept a Date object as input', ()=>{
55
- const result = formatInTimezone(new Date('2026-01-15T04:00:00.000Z'), 'UTC', {
56
- year: 'numeric'
57
- });
58
- expect(result).toBe('2026');
59
- });
60
- });
61
- describe('getTodayInTimezone', ()=>{
62
- it('should return a date string in YYYY-MM-DD format', ()=>{
63
- const result = getTodayInTimezone('UTC');
64
- expect(result).toMatch(/^\d{4}-\d{2}-\d{2}$/);
65
- });
66
- it('should match utcToLocal(now, timezone).date', ()=>{
67
- const now = new Date();
68
- const expected = utcToLocal(now, 'Asia/Dhaka').date;
69
- expect(getTodayInTimezone('Asia/Dhaka')).toBe(expected);
70
- });
71
- });
72
- describe('round-trip', ()=>{
73
- it('should round-trip localToUtc -> utcToLocal for a fixed-offset zone', ()=>{
74
- const utc = localToUtc('2026-03-10', '08:15', 'Asia/Dhaka');
75
- const back = utcToLocal(utc, 'Asia/Dhaka');
76
- expect(back.date).toBe('2026-03-10');
77
- expect(back.time).toBe('08:15');
78
- });
79
- });
80
- });
@@ -1,91 +0,0 @@
1
- const SENSITIVE_KEYS = [
2
- 'password',
3
- 'secret',
4
- 'token',
5
- 'apikey',
6
- 'authorization',
7
- 'salt',
8
- 'hash',
9
- 'credential',
10
- 'accesskey',
11
- 'accountkey',
12
- 'privatekey',
13
- 'connectionstring',
14
- 'passphrase'
15
- ];
16
- /**
17
- * Matched whole, not as a substring - `pass` must be redacted without also
18
- * redacting `bypassCache`, and a storage row's `key` is a path, not a secret.
19
- *
20
- * `config` is the provider settings blob on the storage and email config rows:
21
- * S3, Azure, SFTP and SMTP credentials live in it, so it never leaves the
22
- * process, even though the row itself still publishes.
23
- */ const SENSITIVE_EXACT_KEYS = [
24
- 'pass',
25
- 'pwd',
26
- 'config'
27
- ];
28
- const REDACTED = '[REDACTED]';
29
- const CIRCULAR = '[CIRCULAR]';
30
- const TRUNCATED = '[TRUNCATED]';
31
- const BINARY = '[BINARY]';
32
- const MAX_DEPTH = 8;
33
- /**
34
- * Matches a dot separated event name against a routing pattern.
35
- * `*` matches exactly one segment, `#` and `**` match zero or more segments.
36
- */ export function matchEventPattern(pattern, eventName) {
37
- if (pattern === eventName) return true;
38
- const patternSegments = pattern.split('.');
39
- const nameSegments = eventName.split('.');
40
- return matchSegments(patternSegments, 0, nameSegments, 0);
41
- }
42
- export function isMultiWildcard(segment) {
43
- return segment === '#' || segment === '**';
44
- }
45
- function matchSegments(pattern, patternIndex, name, nameIndex) {
46
- if (patternIndex === pattern.length) return nameIndex === name.length;
47
- const segment = pattern[patternIndex];
48
- if (isMultiWildcard(segment)) {
49
- for(let skip = nameIndex; skip <= name.length; skip++){
50
- if (matchSegments(pattern, patternIndex + 1, name, skip)) return true;
51
- }
52
- return false;
53
- }
54
- if (nameIndex === name.length) return false;
55
- if (segment !== '*' && segment !== name[nameIndex]) return false;
56
- return matchSegments(pattern, patternIndex + 1, name, nameIndex + 1);
57
- }
58
- /**
59
- * Strips credential-like fields before a row leaves the process on an event.
60
- *
61
- * Saved TypeORM rows routinely carry bidirectional relations, so the walk
62
- * tracks the current path and caps its depth - a cycle or a very deep graph
63
- * must never turn an event into a stack overflow.
64
- */ export function sanitizeEventPayload(value) {
65
- return sanitizeValue(value, new WeakSet(), 0);
66
- }
67
- function sanitizeValue(value, ancestors, depth) {
68
- if (value === null || typeof value !== 'object') return value;
69
- if (value instanceof Date) return value;
70
- if (Buffer.isBuffer(value)) return BINARY;
71
- if (ancestors.has(value)) return CIRCULAR;
72
- if (depth >= MAX_DEPTH) return TRUNCATED;
73
- ancestors.add(value);
74
- try {
75
- if (Array.isArray(value)) {
76
- return value.map((item)=>sanitizeValue(item, ancestors, depth + 1));
77
- }
78
- const sanitized = {};
79
- for (const [key, entry] of Object.entries(value)){
80
- sanitized[key] = isSensitiveKey(key) ? REDACTED : sanitizeValue(entry, ancestors, depth + 1);
81
- }
82
- return sanitized;
83
- } finally{
84
- ancestors.delete(value);
85
- }
86
- }
87
- function isSensitiveKey(key) {
88
- const lowered = key.toLowerCase();
89
- if (SENSITIVE_EXACT_KEYS.includes(lowered)) return true;
90
- return SENSITIVE_KEYS.some((sensitive)=>lowered.includes(sensitive));
91
- }
@@ -1,247 +0,0 @@
1
- import { isMultiWildcard, matchEventPattern, sanitizeEventPayload } from './event-pattern.util';
2
- describe('matchEventPattern', ()=>{
3
- it('should match an exact event name', ()=>{
4
- expect(matchEventPattern('storage.folder.created', 'storage.folder.created')).toBe(true);
5
- });
6
- it('should not match a different event name', ()=>{
7
- expect(matchEventPattern('storage.folder.created', 'storage.folder.updated')).toBe(false);
8
- });
9
- it('should treat * as exactly one segment', ()=>{
10
- expect(matchEventPattern('storage.*.created', 'storage.folder.created')).toBe(true);
11
- expect(matchEventPattern('storage.*', 'storage.folder.created')).toBe(false);
12
- });
13
- it('should treat # and ** as any number of segments', ()=>{
14
- expect(matchEventPattern('storage.#', 'storage.folder.created')).toBe(true);
15
- expect(matchEventPattern('**', 'auth.appuser.deleted')).toBe(true);
16
- expect(matchEventPattern('storage.**', 'storage.folder.created')).toBe(true);
17
- });
18
- it('should let a multi wildcard match zero segments', ()=>{
19
- expect(matchEventPattern('storage.folder.created.#', 'storage.folder.created')).toBe(true);
20
- });
21
- it('should not match across a different module', ()=>{
22
- expect(matchEventPattern('storage.#', 'auth.appuser.created')).toBe(false);
23
- });
24
- });
25
- describe('isMultiWildcard', ()=>{
26
- it.each([
27
- [
28
- '#',
29
- true
30
- ],
31
- [
32
- '**',
33
- true
34
- ],
35
- [
36
- '*',
37
- false
38
- ],
39
- [
40
- 'folder',
41
- false
42
- ]
43
- ])('should classify %s as %s', (segment, expected)=>{
44
- expect(isMultiWildcard(segment)).toBe(expected);
45
- });
46
- });
47
- describe('sanitizeEventPayload', ()=>{
48
- it('should redact credential-like fields', ()=>{
49
- const result = sanitizeEventPayload({
50
- id: '1',
51
- password: 'secret',
52
- apiKey: 'k'
53
- });
54
- expect(result).toEqual({
55
- id: '1',
56
- password: '[REDACTED]',
57
- apiKey: '[REDACTED]'
58
- });
59
- });
60
- it('should redact the whole provider settings blob of a storage or email config row', ()=>{
61
- const result = sanitizeEventPayload({
62
- name: 'primary-s3',
63
- provider: 's3',
64
- isActive: true,
65
- config: {
66
- region: 'us-east-1',
67
- bucket: 'assets',
68
- accessKeyId: 'AKIA...',
69
- secretAccessKey: 's3cr3t'
70
- }
71
- });
72
- expect(result).toEqual({
73
- name: 'primary-s3',
74
- provider: 's3',
75
- isActive: true,
76
- config: '[REDACTED]'
77
- });
78
- });
79
- it('should redact the credential keys used by the storage and email providers', ()=>{
80
- const result = sanitizeEventPayload({
81
- settings: {
82
- region: 'us-east-1',
83
- bucket: 'assets',
84
- accessKeyId: 'AKIA...',
85
- secretAccessKey: 's3cr3t',
86
- accountKey: 'azure-key',
87
- privateKey: '-----BEGIN...',
88
- connectionString: 'DefaultEndpointsProtocol=...;AccountKey=abc',
89
- auth: {
90
- user: 'mailer',
91
- pass: 'hunter2'
92
- }
93
- }
94
- });
95
- expect(result).toEqual({
96
- settings: {
97
- region: 'us-east-1',
98
- bucket: 'assets',
99
- accessKeyId: '[REDACTED]',
100
- secretAccessKey: '[REDACTED]',
101
- accountKey: '[REDACTED]',
102
- privateKey: '[REDACTED]',
103
- connectionString: '[REDACTED]',
104
- auth: {
105
- user: 'mailer',
106
- pass: '[REDACTED]'
107
- }
108
- }
109
- });
110
- });
111
- it('should not over-redact keys that merely contain a credential word', ()=>{
112
- const result = sanitizeEventPayload({
113
- key: 'uploads/2026/report.pdf',
114
- bypassCache: true,
115
- passengerCount: 4
116
- });
117
- expect(result).toEqual({
118
- key: 'uploads/2026/report.pdf',
119
- bypassCache: true,
120
- passengerCount: 4
121
- });
122
- });
123
- it('should redact nested fields', ()=>{
124
- const result = sanitizeEventPayload({
125
- user: {
126
- name: 'Ada',
127
- passwordHash: 'x'
128
- }
129
- });
130
- expect(result).toEqual({
131
- user: {
132
- name: 'Ada',
133
- passwordHash: '[REDACTED]'
134
- }
135
- });
136
- });
137
- it('should map over arrays', ()=>{
138
- const result = sanitizeEventPayload([
139
- {
140
- token: 't'
141
- },
142
- {
143
- token: 'u'
144
- }
145
- ]);
146
- expect(result).toEqual([
147
- {
148
- token: '[REDACTED]'
149
- },
150
- {
151
- token: '[REDACTED]'
152
- }
153
- ]);
154
- });
155
- it('should leave dates and primitives untouched', ()=>{
156
- const date = new Date('2026-01-01T00:00:00.000Z');
157
- expect(sanitizeEventPayload({
158
- createdAt: date,
159
- count: 3
160
- })).toEqual({
161
- createdAt: date,
162
- count: 3
163
- });
164
- });
165
- it('should mark a circular relation instead of recursing forever', ()=>{
166
- const folder = {
167
- id: 'folder-1',
168
- name: 'Docs'
169
- };
170
- const file = {
171
- id: 'file-1',
172
- folder
173
- };
174
- folder.files = [
175
- file
176
- ];
177
- expect(sanitizeEventPayload(folder)).toEqual({
178
- id: 'folder-1',
179
- name: 'Docs',
180
- files: [
181
- {
182
- id: 'file-1',
183
- folder: '[CIRCULAR]'
184
- }
185
- ]
186
- });
187
- });
188
- it('should survive a self referencing row', ()=>{
189
- const row = {
190
- id: '1'
191
- };
192
- row.self = row;
193
- expect(()=>sanitizeEventPayload(row)).not.toThrow();
194
- expect(sanitizeEventPayload(row)).toEqual({
195
- id: '1',
196
- self: '[CIRCULAR]'
197
- });
198
- });
199
- it('should repeat a shared row rather than calling the second one circular', ()=>{
200
- const shared = {
201
- id: 'shared'
202
- };
203
- expect(sanitizeEventPayload([
204
- {
205
- a: shared
206
- },
207
- {
208
- b: shared
209
- }
210
- ])).toEqual([
211
- {
212
- a: {
213
- id: 'shared'
214
- }
215
- },
216
- {
217
- b: {
218
- id: 'shared'
219
- }
220
- }
221
- ]);
222
- });
223
- it('should truncate a graph deeper than the depth cap', ()=>{
224
- const deep = {};
225
- let cursor = deep;
226
- for(let level = 0; level < 12; level++){
227
- const next = {};
228
- cursor.child = next;
229
- cursor = next;
230
- }
231
- let result = sanitizeEventPayload(deep);
232
- for(let level = 0; level < 7; level++){
233
- result = result.child;
234
- }
235
- expect(result.child).toBe('[TRUNCATED]');
236
- });
237
- it('should replace a buffer with a marker instead of exploding it into indexes', ()=>{
238
- const result = sanitizeEventPayload({
239
- id: '1',
240
- content: Buffer.from('hello')
241
- });
242
- expect(result).toEqual({
243
- id: '1',
244
- content: '[BINARY]'
245
- });
246
- });
247
- });