@flusys/nestjs-shared 7.1.0 → 8.0.0
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/classes/api-controller.class.d.ts +4 -4
- package/classes/api-service.class.d.ts +7 -7
- package/classes/disabled-event-bus.class.d.ts +1 -1
- package/classes/domain-event.publisher.d.ts +1 -1
- package/classes/event-bus.registry.d.ts +1 -1
- package/classes/event-transports/event-transport.registry.d.ts +1 -1
- package/classes/event-transports/index.d.ts +2 -2
- package/classes/event-transports/kafka-transport.optional.d.ts +1 -1
- package/classes/event-transports/memory-transport.d.ts +1 -1
- package/classes/event-transports/rabbitmq-transport.optional.d.ts +1 -1
- package/classes/hybrid-event-bus.class.d.ts +1 -1
- package/classes/index.d.ts +11 -11
- package/constants/index.d.ts +2 -2
- package/decorators/api-response.decorator.d.ts +1 -1
- package/decorators/current-user.decorator.d.ts +1 -1
- package/decorators/index.d.ts +6 -6
- package/decorators/require-permission.decorator.d.ts +1 -1
- package/dtos/filter-and-pagination.dto.d.ts +1 -1
- package/dtos/index.d.ts +6 -6
- package/entities/index.d.ts +3 -3
- package/enums/index.d.ts +3 -3
- package/exceptions/index.d.ts +2 -2
- package/fesm/470.js +2713 -0
- package/fesm/509.js +793 -0
- package/fesm/667.js +606 -0
- package/fesm/67.js +808 -0
- package/fesm/720.js +914 -0
- package/{cjs/classes/event-transports/rabbitmq-transport.optional.js → fesm/chunks/123.js} +78 -55
- package/fesm/{classes/event-transports/kafka-transport.optional.js → chunks/37.js} +74 -41
- package/fesm/classes/index.js +62 -12
- package/fesm/constants/index.js +445 -17
- package/fesm/decorators/index.js +341 -6
- package/fesm/dtos/index.js +23 -6
- package/fesm/entities/index.js +336 -3
- package/fesm/enums/index.js +57 -3
- package/fesm/exceptions/index.js +280 -2
- package/fesm/guards/index.js +1003 -3
- package/fesm/index.js +1524 -14
- package/fesm/interceptors/index.js +924 -5
- package/fesm/interfaces/index.js +57 -11
- package/fesm/middlewares/index.js +33 -1
- package/fesm/modules/index.js +432 -9
- package/fesm/runtime.js +134 -0
- package/fesm/utils/index.js +1045 -8
- package/filters/global-exception.filter.d.ts +1 -1
- package/filters/index.d.ts +1 -1
- package/guards/index.d.ts +3 -3
- package/guards/jwt-auth.guard.d.ts +1 -1
- package/guards/optional-jwt-auth.guard.d.ts +1 -1
- package/guards/permission.guard.d.ts +2 -2
- package/index.d.ts +14 -14
- package/interceptors/delete-empty-id-from-body.interceptor.d.ts +1 -1
- package/interceptors/idempotency.interceptor.d.ts +2 -2
- package/interceptors/index.d.ts +5 -5
- package/interceptors/response-meta.interceptor.d.ts +1 -1
- package/interceptors/set-user-field-on-body.interceptor.d.ts +1 -1
- package/interceptors/slug.interceptor.d.ts +2 -2
- package/interfaces/ai-assistant-adapter.interface.d.ts +1 -1
- package/interfaces/api.interface.d.ts +2 -2
- package/interfaces/datasource.interface.d.ts +1 -1
- package/interfaces/event-manager-adapter.interface.d.ts +2 -2
- package/interfaces/index.d.ts +11 -11
- package/interfaces/module-config.interface.d.ts +1 -1
- package/interfaces/notification-adapter.interface.d.ts +1 -1
- package/middlewares/index.d.ts +1 -1
- package/middlewares/logger.middleware.d.ts +2 -2
- package/modules/cache/cache.module.d.ts +1 -1
- package/modules/datasource/index.d.ts +1 -1
- package/modules/datasource/multi-tenant-datasource.service.d.ts +4 -4
- package/modules/event-bus/event-bus.explorer.d.ts +2 -2
- package/modules/event-bus/event-bus.module.d.ts +2 -2
- package/modules/event-bus/module-events.provider.d.ts +1 -1
- package/modules/index.d.ts +9 -9
- package/modules/shared-permission-cache/shared-permission-cache.service.d.ts +3 -3
- package/modules/utils/utils.service.d.ts +1 -1
- package/package.json +30 -44
- package/utils/index.d.ts +8 -8
- package/utils/permission-cache-key.util.d.ts +1 -1
- package/utils/query-helpers.util.d.ts +2 -2
- package/utils/request.util.d.ts +1 -1
- package/cjs/classes/api-controller.class.js +0 -728
- package/cjs/classes/api-controller.class.spec.js +0 -684
- package/cjs/classes/api-service.class.js +0 -631
- package/cjs/classes/api-service.class.spec.js +0 -1137
- package/cjs/classes/disabled-event-bus.class.js +0 -15
- package/cjs/classes/disabled-event-bus.class.spec.js +0 -40
- package/cjs/classes/domain-event.publisher.js +0 -76
- package/cjs/classes/domain-event.publisher.spec.js +0 -234
- package/cjs/classes/event-bus.registry.js +0 -68
- package/cjs/classes/event-bus.registry.spec.js +0 -141
- package/cjs/classes/event-transports/event-transport.registry.js +0 -41
- package/cjs/classes/event-transports/event-transport.registry.spec.js +0 -31
- package/cjs/classes/event-transports/index.js +0 -23
- package/cjs/classes/event-transports/kafka-transport.optional.js +0 -151
- package/cjs/classes/event-transports/kafka-transport.optional.spec.js +0 -198
- package/cjs/classes/event-transports/memory-transport.js +0 -53
- package/cjs/classes/event-transports/memory-transport.spec.js +0 -57
- package/cjs/classes/event-transports/rabbitmq-transport.optional.spec.js +0 -255
- package/cjs/classes/handle-custome-db.js +0 -37
- package/cjs/classes/handle-custome-db.spec.js +0 -82
- package/cjs/classes/hybrid-cache.class.js +0 -96
- package/cjs/classes/hybrid-cache.class.spec.js +0 -168
- package/cjs/classes/hybrid-event-bus.class.js +0 -281
- package/cjs/classes/hybrid-event-bus.class.spec.js +0 -218
- package/cjs/classes/index.js +0 -28
- package/cjs/classes/winston.logger.class.js +0 -274
- package/cjs/classes/winston.logger.class.spec.js +0 -330
- package/cjs/constants/index.js +0 -88
- package/cjs/constants/message-keys.js +0 -68
- package/cjs/constants/permissions.js +0 -307
- package/cjs/decorators/api-response.decorator.js +0 -52
- package/cjs/decorators/api-response.decorator.spec.js +0 -126
- package/cjs/decorators/current-user.decorator.js +0 -16
- package/cjs/decorators/current-user.decorator.spec.js +0 -74
- package/cjs/decorators/index.js +0 -23
- package/cjs/decorators/log-action.decorator.js +0 -149
- package/cjs/decorators/log-action.decorator.spec.js +0 -353
- package/cjs/decorators/on-domain-event.decorator.js +0 -13
- package/cjs/decorators/on-domain-event.decorator.spec.js +0 -50
- package/cjs/decorators/public.decorator.js +0 -13
- package/cjs/decorators/public.decorator.spec.js +0 -50
- package/cjs/decorators/require-permission.decorator.js +0 -32
- package/cjs/decorators/require-permission.decorator.spec.js +0 -147
- package/cjs/dtos/delete.dto.js +0 -92
- package/cjs/dtos/filter-and-pagination.dto.js +0 -164
- package/cjs/dtos/get-by-ids.dto.js +0 -65
- package/cjs/dtos/identity-response.dto.js +0 -108
- package/cjs/dtos/index.js +0 -23
- package/cjs/dtos/pagination.dto.js +0 -67
- package/cjs/dtos/response-payload.dto.js +0 -369
- package/cjs/entities/identity.js +0 -100
- package/cjs/entities/index.js +0 -20
- package/cjs/entities/raw-type.js +0 -4
- package/cjs/entities/user-root.js +0 -189
- package/cjs/enums/index.js +0 -20
- package/cjs/enums/notification-type.enum.js +0 -17
- package/cjs/enums/participant-status.enum.js +0 -17
- package/cjs/enums/recurrence-type.enum.js +0 -18
- package/cjs/exceptions/base-app.exception.js +0 -151
- package/cjs/exceptions/base-app.exception.spec.js +0 -157
- package/cjs/exceptions/index.js +0 -19
- package/cjs/exceptions/permission.exception.js +0 -56
- package/cjs/exceptions/permission.exception.spec.js +0 -82
- package/cjs/filters/global-exception.filter.js +0 -279
- package/cjs/filters/global-exception.filter.spec.js +0 -440
- package/cjs/filters/index.js +0 -18
- package/cjs/guards/index.js +0 -20
- package/cjs/guards/jwt-auth.guard.js +0 -75
- package/cjs/guards/jwt-auth.guard.spec.js +0 -75
- package/cjs/guards/optional-jwt-auth.guard.js +0 -67
- package/cjs/guards/optional-jwt-auth.guard.spec.js +0 -55
- package/cjs/guards/permission.guard.js +0 -179
- package/cjs/guards/permission.guard.spec.js +0 -373
- package/cjs/index.js +0 -31
- package/cjs/interceptors/delete-empty-id-from-body.interceptor.js +0 -40
- package/cjs/interceptors/delete-empty-id-from-body.interceptor.spec.js +0 -107
- package/cjs/interceptors/idempotency.interceptor.js +0 -96
- package/cjs/interceptors/idempotency.interceptor.spec.js +0 -116
- package/cjs/interceptors/index.js +0 -22
- package/cjs/interceptors/response-meta.interceptor.js +0 -47
- package/cjs/interceptors/response-meta.interceptor.spec.js +0 -89
- package/cjs/interceptors/set-user-field-on-body.interceptor.js +0 -60
- package/cjs/interceptors/set-user-field-on-body.interceptor.spec.js +0 -128
- package/cjs/interceptors/slug.interceptor.js +0 -75
- package/cjs/interceptors/slug.interceptor.spec.js +0 -110
- package/cjs/interfaces/ai-assistant-adapter.interface.js +0 -24
- package/cjs/interfaces/api.interface.js +0 -4
- package/cjs/interfaces/datasource.interface.js +0 -4
- package/cjs/interfaces/event-bus.interface.js +0 -4
- package/cjs/interfaces/event-manager-adapter.interface.js +0 -11
- package/cjs/interfaces/identity.interface.js +0 -4
- package/cjs/interfaces/index.js +0 -28
- package/cjs/interfaces/logged-user-info.interface.js +0 -6
- package/cjs/interfaces/module-config.interface.js +0 -4
- package/cjs/interfaces/notification-adapter.interface.js +0 -11
- package/cjs/interfaces/permission-sync-adapter.interface.js +0 -11
- package/cjs/interfaces/permission.interface.js +0 -4
- package/cjs/middlewares/index.js +0 -18
- package/cjs/middlewares/logger.middleware.js +0 -264
- package/cjs/middlewares/logger.middleware.spec.js +0 -462
- package/cjs/modules/cache/cache.module.js +0 -39
- package/cjs/modules/cache/cache.module.spec.js +0 -48
- package/cjs/modules/datasource/index.js +0 -18
- package/cjs/modules/datasource/multi-tenant-datasource.service.js +0 -222
- package/cjs/modules/datasource/multi-tenant-datasource.service.spec.js +0 -381
- package/cjs/modules/event-bus/event-bus.explorer.js +0 -124
- package/cjs/modules/event-bus/event-bus.explorer.spec.js +0 -189
- package/cjs/modules/event-bus/event-bus.integration.spec.js +0 -253
- package/cjs/modules/event-bus/event-bus.module.js +0 -94
- package/cjs/modules/event-bus/event-bus.module.spec.js +0 -149
- package/cjs/modules/event-bus/module-events.provider.js +0 -39
- package/cjs/modules/event-bus/module-events.provider.spec.js +0 -56
- package/cjs/modules/index.js +0 -26
- package/cjs/modules/shared-permission-cache/shared-permission-cache.module.js +0 -32
- package/cjs/modules/shared-permission-cache/shared-permission-cache.service.js +0 -101
- package/cjs/modules/shared-permission-cache/shared-permission-cache.service.spec.js +0 -165
- package/cjs/modules/utils/utils.module.js +0 -32
- package/cjs/modules/utils/utils.service.js +0 -76
- package/cjs/modules/utils/utils.service.spec.js +0 -169
- package/cjs/utils/date-time.util.js +0 -94
- package/cjs/utils/date-time.util.spec.js +0 -84
- package/cjs/utils/event-pattern.util.js +0 -103
- package/cjs/utils/event-pattern.util.spec.js +0 -251
- package/cjs/utils/html-sanitizer.util.js +0 -64
- package/cjs/utils/html-sanitizer.util.spec.js +0 -76
- package/cjs/utils/index.js +0 -25
- package/cjs/utils/optional-module.util.js +0 -35
- package/cjs/utils/optional-module.util.spec.js +0 -14
- package/cjs/utils/permission-cache-key.util.js +0 -31
- package/cjs/utils/permission-cache-key.util.spec.js +0 -88
- package/cjs/utils/query-helpers.util.js +0 -60
- package/cjs/utils/query-helpers.util.spec.js +0 -209
- package/cjs/utils/request.util.js +0 -96
- package/cjs/utils/request.util.spec.js +0 -249
- package/cjs/utils/string.util.js +0 -63
- package/cjs/utils/string.util.spec.js +0 -63
- package/fesm/classes/api-controller.class.js +0 -718
- package/fesm/classes/api-controller.class.spec.js +0 -680
- package/fesm/classes/api-service.class.js +0 -621
- package/fesm/classes/api-service.class.spec.js +0 -1133
- package/fesm/classes/disabled-event-bus.class.js +0 -11
- package/fesm/classes/disabled-event-bus.class.spec.js +0 -36
- package/fesm/classes/domain-event.publisher.js +0 -63
- package/fesm/classes/domain-event.publisher.spec.js +0 -230
- package/fesm/classes/event-bus.registry.js +0 -64
- package/fesm/classes/event-bus.registry.spec.js +0 -137
- package/fesm/classes/event-transports/event-transport.registry.js +0 -35
- package/fesm/classes/event-transports/event-transport.registry.spec.js +0 -27
- package/fesm/classes/event-transports/index.js +0 -6
- package/fesm/classes/event-transports/kafka-transport.optional.spec.js +0 -194
- package/fesm/classes/event-transports/memory-transport.js +0 -49
- package/fesm/classes/event-transports/memory-transport.spec.js +0 -53
- package/fesm/classes/event-transports/rabbitmq-transport.optional.js +0 -174
- package/fesm/classes/event-transports/rabbitmq-transport.optional.spec.js +0 -251
- package/fesm/classes/handle-custome-db.js +0 -19
- package/fesm/classes/handle-custome-db.spec.js +0 -78
- package/fesm/classes/hybrid-cache.class.js +0 -81
- package/fesm/classes/hybrid-cache.class.spec.js +0 -164
- package/fesm/classes/hybrid-event-bus.class.js +0 -237
- package/fesm/classes/hybrid-event-bus.class.spec.js +0 -214
- package/fesm/classes/winston.logger.class.js +0 -228
- package/fesm/classes/winston.logger.class.spec.js +0 -327
- package/fesm/constants/message-keys.js +0 -49
- package/fesm/constants/permissions.js +0 -215
- package/fesm/decorators/api-response.decorator.js +0 -42
- package/fesm/decorators/api-response.decorator.spec.js +0 -122
- package/fesm/decorators/current-user.decorator.js +0 -18
- package/fesm/decorators/current-user.decorator.spec.js +0 -73
- package/fesm/decorators/log-action.decorator.js +0 -139
- package/fesm/decorators/log-action.decorator.spec.js +0 -349
- package/fesm/decorators/on-domain-event.decorator.js +0 -10
- package/fesm/decorators/on-domain-event.decorator.spec.js +0 -46
- package/fesm/decorators/public.decorator.js +0 -20
- package/fesm/decorators/public.decorator.spec.js +0 -46
- package/fesm/decorators/require-permission.decorator.js +0 -27
- package/fesm/decorators/require-permission.decorator.spec.js +0 -143
- package/fesm/dtos/delete.dto.js +0 -82
- package/fesm/dtos/filter-and-pagination.dto.js +0 -148
- package/fesm/dtos/get-by-ids.dto.js +0 -55
- package/fesm/dtos/identity-response.dto.js +0 -98
- package/fesm/dtos/pagination.dto.js +0 -57
- package/fesm/dtos/response-payload.dto.js +0 -336
- package/fesm/entities/identity.js +0 -90
- package/fesm/entities/raw-type.js +0 -1
- package/fesm/entities/user-root.js +0 -179
- package/fesm/enums/notification-type.enum.js +0 -7
- package/fesm/enums/participant-status.enum.js +0 -7
- package/fesm/enums/recurrence-type.enum.js +0 -8
- package/fesm/exceptions/base-app.exception.js +0 -115
- package/fesm/exceptions/base-app.exception.spec.js +0 -153
- package/fesm/exceptions/permission.exception.js +0 -35
- package/fesm/exceptions/permission.exception.spec.js +0 -78
- package/fesm/filters/global-exception.filter.js +0 -269
- package/fesm/filters/global-exception.filter.spec.js +0 -436
- package/fesm/filters/index.js +0 -1
- package/fesm/guards/jwt-auth.guard.js +0 -65
- package/fesm/guards/jwt-auth.guard.spec.js +0 -71
- package/fesm/guards/optional-jwt-auth.guard.js +0 -57
- package/fesm/guards/optional-jwt-auth.guard.spec.js +0 -51
- package/fesm/guards/permission.guard.js +0 -169
- package/fesm/guards/permission.guard.spec.js +0 -369
- package/fesm/interceptors/delete-empty-id-from-body.interceptor.js +0 -30
- package/fesm/interceptors/delete-empty-id-from-body.interceptor.spec.js +0 -103
- package/fesm/interceptors/idempotency.interceptor.js +0 -86
- package/fesm/interceptors/idempotency.interceptor.spec.js +0 -112
- package/fesm/interceptors/response-meta.interceptor.js +0 -37
- package/fesm/interceptors/response-meta.interceptor.spec.js +0 -85
- package/fesm/interceptors/set-user-field-on-body.interceptor.js +0 -39
- package/fesm/interceptors/set-user-field-on-body.interceptor.spec.js +0 -124
- package/fesm/interceptors/slug.interceptor.js +0 -65
- package/fesm/interceptors/slug.interceptor.spec.js +0 -106
- package/fesm/interfaces/ai-assistant-adapter.interface.js +0 -3
- package/fesm/interfaces/api.interface.js +0 -1
- package/fesm/interfaces/datasource.interface.js +0 -1
- package/fesm/interfaces/event-bus.interface.js +0 -1
- package/fesm/interfaces/event-manager-adapter.interface.js +0 -1
- package/fesm/interfaces/identity.interface.js +0 -1
- package/fesm/interfaces/logged-user-info.interface.js +0 -3
- package/fesm/interfaces/module-config.interface.js +0 -5
- package/fesm/interfaces/notification-adapter.interface.js +0 -1
- package/fesm/interfaces/permission-sync-adapter.interface.js +0 -1
- package/fesm/interfaces/permission.interface.js +0 -1
- package/fesm/middlewares/logger.middleware.js +0 -235
- package/fesm/middlewares/logger.middleware.spec.js +0 -459
- package/fesm/modules/cache/cache.module.js +0 -29
- package/fesm/modules/cache/cache.module.spec.js +0 -44
- package/fesm/modules/datasource/index.js +0 -1
- package/fesm/modules/datasource/multi-tenant-datasource.service.js +0 -212
- package/fesm/modules/datasource/multi-tenant-datasource.service.spec.js +0 -377
- package/fesm/modules/event-bus/event-bus.explorer.js +0 -114
- package/fesm/modules/event-bus/event-bus.explorer.spec.js +0 -185
- package/fesm/modules/event-bus/event-bus.integration.spec.js +0 -249
- package/fesm/modules/event-bus/event-bus.module.js +0 -84
- package/fesm/modules/event-bus/event-bus.module.spec.js +0 -145
- package/fesm/modules/event-bus/module-events.provider.js +0 -26
- package/fesm/modules/event-bus/module-events.provider.spec.js +0 -52
- package/fesm/modules/shared-permission-cache/shared-permission-cache.module.js +0 -22
- package/fesm/modules/shared-permission-cache/shared-permission-cache.service.js +0 -91
- package/fesm/modules/shared-permission-cache/shared-permission-cache.service.spec.js +0 -161
- package/fesm/modules/utils/utils.module.js +0 -22
- package/fesm/modules/utils/utils.service.js +0 -66
- package/fesm/modules/utils/utils.service.spec.js +0 -165
- package/fesm/utils/date-time.util.js +0 -70
- package/fesm/utils/date-time.util.spec.js +0 -80
- package/fesm/utils/event-pattern.util.js +0 -91
- package/fesm/utils/event-pattern.util.spec.js +0 -247
- package/fesm/utils/html-sanitizer.util.js +0 -69
- package/fesm/utils/html-sanitizer.util.spec.js +0 -72
- package/fesm/utils/optional-module.util.js +0 -25
- package/fesm/utils/optional-module.util.spec.js +0 -10
- package/fesm/utils/permission-cache-key.util.js +0 -10
- package/fesm/utils/permission-cache-key.util.spec.js +0 -84
- package/fesm/utils/query-helpers.util.js +0 -85
- package/fesm/utils/query-helpers.util.spec.js +0 -205
- package/fesm/utils/request.util.js +0 -81
- package/fesm/utils/request.util.spec.js +0 -245
- package/fesm/utils/string.util.js +0 -71
- package/fesm/utils/string.util.spec.js +0 -59
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
function _define_property(obj, key, value) {
|
|
2
|
-
if (key in obj) {
|
|
3
|
-
Object.defineProperty(obj, key, {
|
|
4
|
-
value: value,
|
|
5
|
-
enumerable: true,
|
|
6
|
-
configurable: true,
|
|
7
|
-
writable: true
|
|
8
|
-
});
|
|
9
|
-
} else {
|
|
10
|
-
obj[key] = value;
|
|
11
|
-
}
|
|
12
|
-
return obj;
|
|
13
|
-
}
|
|
14
|
-
function _ts_decorate(decorators, target, key, desc) {
|
|
15
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
16
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
17
|
-
else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
18
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
19
|
-
}
|
|
20
|
-
function _ts_metadata(k, v) {
|
|
21
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
22
|
-
}
|
|
23
|
-
function _ts_param(paramIndex, decorator) {
|
|
24
|
-
return function(target, key) {
|
|
25
|
-
decorator(target, key, paramIndex);
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
import { ConflictException, Inject, Injectable, Optional } from '@nestjs/common';
|
|
29
|
-
import { of } from 'rxjs';
|
|
30
|
-
import { tap } from 'rxjs/operators';
|
|
31
|
-
import { HybridCache } from '../classes/hybrid-cache.class';
|
|
32
|
-
import { CACHE_INSTANCE, IDEMPOTENCY_CACHE_PREFIX, IDEMPOTENCY_KEY_HEADER, SYSTEM_MESSAGES } from '../constants';
|
|
33
|
-
export class IdempotencyInterceptor {
|
|
34
|
-
async intercept(context, next) {
|
|
35
|
-
// Skip if no cache available
|
|
36
|
-
if (!this.cache) {
|
|
37
|
-
return next.handle();
|
|
38
|
-
}
|
|
39
|
-
const request = context.switchToHttp().getRequest();
|
|
40
|
-
const idempotencyKey = request.headers[IDEMPOTENCY_KEY_HEADER];
|
|
41
|
-
// Skip if no idempotency key provided
|
|
42
|
-
if (!idempotencyKey) {
|
|
43
|
-
return next.handle();
|
|
44
|
-
}
|
|
45
|
-
const cacheKey = `${IDEMPOTENCY_CACHE_PREFIX}:${idempotencyKey}`;
|
|
46
|
-
// Check if request already exists
|
|
47
|
-
const cached = await this.cache.get(cacheKey);
|
|
48
|
-
if (cached) {
|
|
49
|
-
// If still processing, throw conflict
|
|
50
|
-
if (cached === this.PROCESSING_MARKER) {
|
|
51
|
-
throw new ConflictException({
|
|
52
|
-
success: false,
|
|
53
|
-
message: 'Request is already being processed',
|
|
54
|
-
messageKey: SYSTEM_MESSAGES.DUPLICATE_REQUEST
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
// Return cached response
|
|
58
|
-
return of(cached);
|
|
59
|
-
}
|
|
60
|
-
// Mark as processing
|
|
61
|
-
const cache = this.cache;
|
|
62
|
-
await cache.set(cacheKey, this.PROCESSING_MARKER, this.CACHE_TTL);
|
|
63
|
-
// Process request and cache response
|
|
64
|
-
return next.handle().pipe(tap(async (response)=>{
|
|
65
|
-
// Cache the successful response
|
|
66
|
-
await cache.set(cacheKey, response, this.CACHE_TTL);
|
|
67
|
-
}));
|
|
68
|
-
}
|
|
69
|
-
constructor(cache){
|
|
70
|
-
_define_property(this, "cache", void 0);
|
|
71
|
-
_define_property(this, "CACHE_TTL", void 0); // 24 hours
|
|
72
|
-
_define_property(this, "PROCESSING_MARKER", void 0);
|
|
73
|
-
this.cache = cache;
|
|
74
|
-
this.CACHE_TTL = 24 * 60 * 60 * 1000;
|
|
75
|
-
this.PROCESSING_MARKER = '__PROCESSING__';
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
IdempotencyInterceptor = _ts_decorate([
|
|
79
|
-
Injectable(),
|
|
80
|
-
_ts_param(0, Optional()),
|
|
81
|
-
_ts_param(0, Inject(CACHE_INSTANCE)),
|
|
82
|
-
_ts_metadata("design:type", Function),
|
|
83
|
-
_ts_metadata("design:paramtypes", [
|
|
84
|
-
typeof HybridCache === "undefined" ? Object : HybridCache
|
|
85
|
-
])
|
|
86
|
-
], IdempotencyInterceptor);
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
import { ConflictException } from '@nestjs/common';
|
|
2
|
-
import { of } from 'rxjs';
|
|
3
|
-
import { IDEMPOTENCY_CACHE_PREFIX, IDEMPOTENCY_KEY_HEADER } from '../constants';
|
|
4
|
-
import { IdempotencyInterceptor } from './idempotency.interceptor';
|
|
5
|
-
function buildContext(headers = {}) {
|
|
6
|
-
const request = {
|
|
7
|
-
headers
|
|
8
|
-
};
|
|
9
|
-
return {
|
|
10
|
-
switchToHttp: ()=>({
|
|
11
|
-
getRequest: ()=>request
|
|
12
|
-
})
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
function buildCallHandler(response = {
|
|
16
|
-
success: true
|
|
17
|
-
}) {
|
|
18
|
-
return {
|
|
19
|
-
handle: jest.fn().mockReturnValue(of(response))
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
describe('IdempotencyInterceptor', ()=>{
|
|
23
|
-
let cache;
|
|
24
|
-
beforeEach(()=>{
|
|
25
|
-
cache = {
|
|
26
|
-
get: jest.fn(),
|
|
27
|
-
set: jest.fn(),
|
|
28
|
-
del: jest.fn()
|
|
29
|
-
};
|
|
30
|
-
});
|
|
31
|
-
it('should skip idempotency handling when no cache is injected', async ()=>{
|
|
32
|
-
const interceptor = new IdempotencyInterceptor(undefined);
|
|
33
|
-
const callHandler = buildCallHandler('raw-result');
|
|
34
|
-
const result$ = await interceptor.intercept(buildContext({
|
|
35
|
-
[IDEMPOTENCY_KEY_HEADER]: 'key-1'
|
|
36
|
-
}), callHandler);
|
|
37
|
-
await new Promise((resolve)=>{
|
|
38
|
-
result$.subscribe((value)=>{
|
|
39
|
-
expect(value).toBe('raw-result');
|
|
40
|
-
resolve();
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
expect(callHandler.handle).toHaveBeenCalled();
|
|
44
|
-
});
|
|
45
|
-
it('should skip idempotency handling when no idempotency key header is provided', async ()=>{
|
|
46
|
-
const interceptor = new IdempotencyInterceptor(cache);
|
|
47
|
-
const callHandler = buildCallHandler('raw-result');
|
|
48
|
-
const result$ = await interceptor.intercept(buildContext({}), callHandler);
|
|
49
|
-
await new Promise((resolve)=>{
|
|
50
|
-
result$.subscribe((value)=>{
|
|
51
|
-
expect(value).toBe('raw-result');
|
|
52
|
-
resolve();
|
|
53
|
-
});
|
|
54
|
-
});
|
|
55
|
-
expect(cache.get).not.toHaveBeenCalled();
|
|
56
|
-
});
|
|
57
|
-
it('should process and cache the response when the key is new', async ()=>{
|
|
58
|
-
cache.get.mockResolvedValue(undefined);
|
|
59
|
-
const interceptor = new IdempotencyInterceptor(cache);
|
|
60
|
-
const callHandler = buildCallHandler({
|
|
61
|
-
success: true,
|
|
62
|
-
data: 'X'
|
|
63
|
-
});
|
|
64
|
-
const result$ = await interceptor.intercept(buildContext({
|
|
65
|
-
[IDEMPOTENCY_KEY_HEADER]: 'key-1'
|
|
66
|
-
}), callHandler);
|
|
67
|
-
const cacheKey = `${IDEMPOTENCY_CACHE_PREFIX}:key-1`;
|
|
68
|
-
expect(cache.set).toHaveBeenCalledWith(cacheKey, '__PROCESSING__', 24 * 60 * 60 * 1000);
|
|
69
|
-
await new Promise((resolve)=>{
|
|
70
|
-
result$.subscribe((value)=>{
|
|
71
|
-
expect(value).toEqual({
|
|
72
|
-
success: true,
|
|
73
|
-
data: 'X'
|
|
74
|
-
});
|
|
75
|
-
resolve();
|
|
76
|
-
});
|
|
77
|
-
});
|
|
78
|
-
// Allow the tap() side-effect microtask to flush
|
|
79
|
-
await Promise.resolve();
|
|
80
|
-
await Promise.resolve();
|
|
81
|
-
expect(cache.set).toHaveBeenCalledWith(cacheKey, {
|
|
82
|
-
success: true,
|
|
83
|
-
data: 'X'
|
|
84
|
-
}, 24 * 60 * 60 * 1000);
|
|
85
|
-
});
|
|
86
|
-
it('should return the cached response when the key already has a completed result', async ()=>{
|
|
87
|
-
const cachedResponse = {
|
|
88
|
-
success: true,
|
|
89
|
-
data: 'cached'
|
|
90
|
-
};
|
|
91
|
-
cache.get.mockResolvedValue(cachedResponse);
|
|
92
|
-
const interceptor = new IdempotencyInterceptor(cache);
|
|
93
|
-
const callHandler = buildCallHandler();
|
|
94
|
-
const result$ = await interceptor.intercept(buildContext({
|
|
95
|
-
[IDEMPOTENCY_KEY_HEADER]: 'key-1'
|
|
96
|
-
}), callHandler);
|
|
97
|
-
await new Promise((resolve)=>{
|
|
98
|
-
result$.subscribe((value)=>{
|
|
99
|
-
expect(value).toEqual(cachedResponse);
|
|
100
|
-
resolve();
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
|
-
expect(callHandler.handle).not.toHaveBeenCalled();
|
|
104
|
-
});
|
|
105
|
-
it('should throw ConflictException when the key is still marked as processing', async ()=>{
|
|
106
|
-
cache.get.mockResolvedValue('__PROCESSING__');
|
|
107
|
-
const interceptor = new IdempotencyInterceptor(cache);
|
|
108
|
-
await expect(interceptor.intercept(buildContext({
|
|
109
|
-
[IDEMPOTENCY_KEY_HEADER]: 'key-1'
|
|
110
|
-
}), buildCallHandler())).rejects.toBeInstanceOf(ConflictException);
|
|
111
|
-
});
|
|
112
|
-
});
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
function _ts_decorate(decorators, target, key, desc) {
|
|
2
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
-
else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
-
}
|
|
7
|
-
import { Injectable } from '@nestjs/common';
|
|
8
|
-
import { randomUUID } from 'crypto';
|
|
9
|
-
import { map } from 'rxjs/operators';
|
|
10
|
-
import { REQUEST_ID_HEADER } from '../constants';
|
|
11
|
-
export class ResponseMetaInterceptor {
|
|
12
|
-
intercept(context, next) {
|
|
13
|
-
const request = context.switchToHttp().getRequest();
|
|
14
|
-
const startTime = Date.now();
|
|
15
|
-
// Generate or use existing request ID
|
|
16
|
-
const requestId = request.headers[REQUEST_ID_HEADER] || `req_${randomUUID().slice(0, 12)}`;
|
|
17
|
-
// Store request ID for logging
|
|
18
|
-
request.requestId = requestId;
|
|
19
|
-
return next.handle().pipe(map((response)=>{
|
|
20
|
-
// Only add metadata if response is an object with success field
|
|
21
|
-
if (response && typeof response === 'object' && 'success' in response) {
|
|
22
|
-
return {
|
|
23
|
-
...response,
|
|
24
|
-
_meta: {
|
|
25
|
-
requestId,
|
|
26
|
-
timestamp: new Date().toISOString(),
|
|
27
|
-
responseTime: Date.now() - startTime
|
|
28
|
-
}
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
return response;
|
|
32
|
-
}));
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
ResponseMetaInterceptor = _ts_decorate([
|
|
36
|
-
Injectable()
|
|
37
|
-
], ResponseMetaInterceptor);
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import { of } from 'rxjs';
|
|
2
|
-
import { REQUEST_ID_HEADER } from '../constants';
|
|
3
|
-
import { ResponseMetaInterceptor } from './response-meta.interceptor';
|
|
4
|
-
function buildContext(headers = {}) {
|
|
5
|
-
const request = {
|
|
6
|
-
headers
|
|
7
|
-
};
|
|
8
|
-
const context = {
|
|
9
|
-
switchToHttp: ()=>({
|
|
10
|
-
getRequest: ()=>request
|
|
11
|
-
})
|
|
12
|
-
};
|
|
13
|
-
return {
|
|
14
|
-
context,
|
|
15
|
-
request
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
function buildCallHandler(response) {
|
|
19
|
-
return {
|
|
20
|
-
handle: jest.fn().mockReturnValue(of(response))
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
describe('ResponseMetaInterceptor', ()=>{
|
|
24
|
-
let interceptor;
|
|
25
|
-
beforeEach(()=>{
|
|
26
|
-
interceptor = new ResponseMetaInterceptor();
|
|
27
|
-
});
|
|
28
|
-
it('should attach _meta to a response object with a success field', (done)=>{
|
|
29
|
-
const { context } = buildContext();
|
|
30
|
-
interceptor.intercept(context, buildCallHandler({
|
|
31
|
-
success: true,
|
|
32
|
-
data: {}
|
|
33
|
-
})).subscribe((result)=>{
|
|
34
|
-
expect(result.success).toBe(true);
|
|
35
|
-
expect(result._meta).toMatchObject({
|
|
36
|
-
requestId: expect.stringMatching(/^req_/),
|
|
37
|
-
timestamp: expect.any(String),
|
|
38
|
-
responseTime: expect.any(Number)
|
|
39
|
-
});
|
|
40
|
-
done();
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
it('should use the existing x-request-id header instead of generating one', (done)=>{
|
|
44
|
-
const { context } = buildContext({
|
|
45
|
-
[REQUEST_ID_HEADER]: 'existing-id'
|
|
46
|
-
});
|
|
47
|
-
interceptor.intercept(context, buildCallHandler({
|
|
48
|
-
success: true
|
|
49
|
-
})).subscribe((result)=>{
|
|
50
|
-
expect(result._meta.requestId).toBe('existing-id');
|
|
51
|
-
done();
|
|
52
|
-
});
|
|
53
|
-
});
|
|
54
|
-
it('should set request.requestId as a side effect', ()=>{
|
|
55
|
-
const { context, request } = buildContext();
|
|
56
|
-
interceptor.intercept(context, buildCallHandler({
|
|
57
|
-
success: true
|
|
58
|
-
})).subscribe();
|
|
59
|
-
expect(request.requestId).toEqual(expect.stringMatching(/^req_/));
|
|
60
|
-
});
|
|
61
|
-
it('should not modify a response without a "success" field', (done)=>{
|
|
62
|
-
const { context } = buildContext();
|
|
63
|
-
const response = {
|
|
64
|
-
data: 'raw'
|
|
65
|
-
};
|
|
66
|
-
interceptor.intercept(context, buildCallHandler(response)).subscribe((result)=>{
|
|
67
|
-
expect(result).toBe(response);
|
|
68
|
-
done();
|
|
69
|
-
});
|
|
70
|
-
});
|
|
71
|
-
it('should not modify a primitive response', (done)=>{
|
|
72
|
-
const { context } = buildContext();
|
|
73
|
-
interceptor.intercept(context, buildCallHandler('plain-string')).subscribe((result)=>{
|
|
74
|
-
expect(result).toBe('plain-string');
|
|
75
|
-
done();
|
|
76
|
-
});
|
|
77
|
-
});
|
|
78
|
-
it('should not modify a null response', (done)=>{
|
|
79
|
-
const { context } = buildContext();
|
|
80
|
-
interceptor.intercept(context, buildCallHandler(null)).subscribe((result)=>{
|
|
81
|
-
expect(result).toBeNull();
|
|
82
|
-
done();
|
|
83
|
-
});
|
|
84
|
-
});
|
|
85
|
-
});
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
function _ts_decorate(decorators, target, key, desc) {
|
|
2
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
-
else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
-
}
|
|
7
|
-
import { Injectable } from '@nestjs/common';
|
|
8
|
-
/**
|
|
9
|
-
* Factory function to create interceptors that set user ID fields on request body
|
|
10
|
-
* @param fieldName - The field name to set (e.g., 'createdById', 'updatedById', 'deletedById')
|
|
11
|
-
*/ export function createSetUserFieldInterceptor(fieldName) {
|
|
12
|
-
let SetUserFieldOnBody = class SetUserFieldOnBody {
|
|
13
|
-
intercept(context, next) {
|
|
14
|
-
const request = context.switchToHttp().getRequest();
|
|
15
|
-
const user = request?.user;
|
|
16
|
-
if (user) {
|
|
17
|
-
if (Array.isArray(request.body)) {
|
|
18
|
-
request.body = request.body.map((item)=>({
|
|
19
|
-
...item,
|
|
20
|
-
[fieldName]: user.id
|
|
21
|
-
}));
|
|
22
|
-
} else if (typeof request.body === 'object' && request.body !== null) {
|
|
23
|
-
request.body = {
|
|
24
|
-
...request.body,
|
|
25
|
-
[fieldName]: user.id
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
return next.handle();
|
|
30
|
-
}
|
|
31
|
-
};
|
|
32
|
-
SetUserFieldOnBody = _ts_decorate([
|
|
33
|
-
Injectable()
|
|
34
|
-
], SetUserFieldOnBody);
|
|
35
|
-
return SetUserFieldOnBody;
|
|
36
|
-
}
|
|
37
|
-
/** Sets createdById field on request body from authenticated user */ export const SetCreatedByOnBody = createSetUserFieldInterceptor('createdById');
|
|
38
|
-
/** Sets updatedById field on request body from authenticated user */ export const SetUpdateByOnBody = createSetUserFieldInterceptor('updatedById');
|
|
39
|
-
/** Sets deletedById field on request body from authenticated user */ export const SetDeletedByOnBody = createSetUserFieldInterceptor('deletedById');
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
import { of } from 'rxjs';
|
|
2
|
-
import { createSetUserFieldInterceptor, SetCreatedByOnBody, SetDeletedByOnBody, SetUpdateByOnBody } from './set-user-field-on-body.interceptor';
|
|
3
|
-
function buildContext(body, user) {
|
|
4
|
-
const request = {
|
|
5
|
-
body,
|
|
6
|
-
user
|
|
7
|
-
};
|
|
8
|
-
const context = {
|
|
9
|
-
switchToHttp: ()=>({
|
|
10
|
-
getRequest: ()=>request
|
|
11
|
-
})
|
|
12
|
-
};
|
|
13
|
-
return {
|
|
14
|
-
context,
|
|
15
|
-
request
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
function buildCallHandler() {
|
|
19
|
-
return {
|
|
20
|
-
handle: jest.fn().mockReturnValue(of('next-result'))
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
describe('createSetUserFieldInterceptor', ()=>{
|
|
24
|
-
it('should set the field on a single object body from the authenticated user', ()=>{
|
|
25
|
-
const Interceptor = createSetUserFieldInterceptor('createdById');
|
|
26
|
-
const interceptor = new Interceptor();
|
|
27
|
-
const { context, request } = buildContext({
|
|
28
|
-
name: 'Product'
|
|
29
|
-
}, {
|
|
30
|
-
id: 'user-1'
|
|
31
|
-
});
|
|
32
|
-
interceptor.intercept(context, buildCallHandler());
|
|
33
|
-
expect(request.body).toEqual({
|
|
34
|
-
name: 'Product',
|
|
35
|
-
createdById: 'user-1'
|
|
36
|
-
});
|
|
37
|
-
});
|
|
38
|
-
it('should set the field on every item of an array body', ()=>{
|
|
39
|
-
const Interceptor = createSetUserFieldInterceptor('updatedById');
|
|
40
|
-
const interceptor = new Interceptor();
|
|
41
|
-
const { context, request } = buildContext([
|
|
42
|
-
{
|
|
43
|
-
name: 'A'
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
|
-
name: 'B'
|
|
47
|
-
}
|
|
48
|
-
], {
|
|
49
|
-
id: 'user-2'
|
|
50
|
-
});
|
|
51
|
-
interceptor.intercept(context, buildCallHandler());
|
|
52
|
-
expect(request.body).toEqual([
|
|
53
|
-
{
|
|
54
|
-
name: 'A',
|
|
55
|
-
updatedById: 'user-2'
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
name: 'B',
|
|
59
|
-
updatedById: 'user-2'
|
|
60
|
-
}
|
|
61
|
-
]);
|
|
62
|
-
});
|
|
63
|
-
it('should not modify the body when there is no authenticated user', ()=>{
|
|
64
|
-
const Interceptor = createSetUserFieldInterceptor('deletedById');
|
|
65
|
-
const interceptor = new Interceptor();
|
|
66
|
-
const { context, request } = buildContext({
|
|
67
|
-
name: 'Product'
|
|
68
|
-
}, undefined);
|
|
69
|
-
interceptor.intercept(context, buildCallHandler());
|
|
70
|
-
expect(request.body).toEqual({
|
|
71
|
-
name: 'Product'
|
|
72
|
-
});
|
|
73
|
-
});
|
|
74
|
-
it('should not throw when body is null and there is no user', ()=>{
|
|
75
|
-
const Interceptor = createSetUserFieldInterceptor('createdById');
|
|
76
|
-
const interceptor = new Interceptor();
|
|
77
|
-
const { context, request } = buildContext(null, undefined);
|
|
78
|
-
expect(()=>interceptor.intercept(context, buildCallHandler())).not.toThrow();
|
|
79
|
-
expect(request.body).toBeNull();
|
|
80
|
-
});
|
|
81
|
-
it('should return next.handle() observable', (done)=>{
|
|
82
|
-
const Interceptor = createSetUserFieldInterceptor('createdById');
|
|
83
|
-
const interceptor = new Interceptor();
|
|
84
|
-
const { context } = buildContext({}, {
|
|
85
|
-
id: 'user-1'
|
|
86
|
-
});
|
|
87
|
-
interceptor.intercept(context, buildCallHandler()).subscribe((value)=>{
|
|
88
|
-
expect(value).toBe('next-result');
|
|
89
|
-
done();
|
|
90
|
-
});
|
|
91
|
-
});
|
|
92
|
-
});
|
|
93
|
-
describe('preconfigured user-field interceptors', ()=>{
|
|
94
|
-
it('should set createdById via SetCreatedByOnBody', ()=>{
|
|
95
|
-
const interceptor = new SetCreatedByOnBody();
|
|
96
|
-
const { context, request } = buildContext({}, {
|
|
97
|
-
id: 'user-1'
|
|
98
|
-
});
|
|
99
|
-
interceptor.intercept(context, buildCallHandler());
|
|
100
|
-
expect(request.body).toEqual({
|
|
101
|
-
createdById: 'user-1'
|
|
102
|
-
});
|
|
103
|
-
});
|
|
104
|
-
it('should set updatedById via SetUpdateByOnBody', ()=>{
|
|
105
|
-
const interceptor = new SetUpdateByOnBody();
|
|
106
|
-
const { context, request } = buildContext({}, {
|
|
107
|
-
id: 'user-1'
|
|
108
|
-
});
|
|
109
|
-
interceptor.intercept(context, buildCallHandler());
|
|
110
|
-
expect(request.body).toEqual({
|
|
111
|
-
updatedById: 'user-1'
|
|
112
|
-
});
|
|
113
|
-
});
|
|
114
|
-
it('should set deletedById via SetDeletedByOnBody', ()=>{
|
|
115
|
-
const interceptor = new SetDeletedByOnBody();
|
|
116
|
-
const { context, request } = buildContext({}, {
|
|
117
|
-
id: 'user-1'
|
|
118
|
-
});
|
|
119
|
-
interceptor.intercept(context, buildCallHandler());
|
|
120
|
-
expect(request.body).toEqual({
|
|
121
|
-
deletedById: 'user-1'
|
|
122
|
-
});
|
|
123
|
-
});
|
|
124
|
-
});
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
function _define_property(obj, key, value) {
|
|
2
|
-
if (key in obj) {
|
|
3
|
-
Object.defineProperty(obj, key, {
|
|
4
|
-
value: value,
|
|
5
|
-
enumerable: true,
|
|
6
|
-
configurable: true,
|
|
7
|
-
writable: true
|
|
8
|
-
});
|
|
9
|
-
} else {
|
|
10
|
-
obj[key] = value;
|
|
11
|
-
}
|
|
12
|
-
return obj;
|
|
13
|
-
}
|
|
14
|
-
function _ts_decorate(decorators, target, key, desc) {
|
|
15
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
16
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
17
|
-
else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
18
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
19
|
-
}
|
|
20
|
-
function _ts_metadata(k, v) {
|
|
21
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
22
|
-
}
|
|
23
|
-
function _ts_param(paramIndex, decorator) {
|
|
24
|
-
return function(target, key) {
|
|
25
|
-
decorator(target, key, paramIndex);
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
import { Inject, Injectable } from '@nestjs/common';
|
|
29
|
-
import { UtilsService } from '../modules/utils/utils.service';
|
|
30
|
-
export class Slug {
|
|
31
|
-
intercept(context, next) {
|
|
32
|
-
const request = context.switchToHttp().getRequest();
|
|
33
|
-
if (Array.isArray(request.body)) {
|
|
34
|
-
request.body = request.body.map((item)=>{
|
|
35
|
-
// Only generate slug if not provided and name exists
|
|
36
|
-
if (!item.slug && item?.name) {
|
|
37
|
-
return {
|
|
38
|
-
...item,
|
|
39
|
-
slug: this.utilsService.transformToSlug(item.name)
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
return item;
|
|
43
|
-
});
|
|
44
|
-
} else if (!request.body?.slug && request.body?.name) {
|
|
45
|
-
// Only generate slug if not provided and name exists
|
|
46
|
-
request.body = {
|
|
47
|
-
...request.body,
|
|
48
|
-
slug: this.utilsService.transformToSlug(request.body.name)
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
return next.handle();
|
|
52
|
-
}
|
|
53
|
-
constructor(utilsService){
|
|
54
|
-
_define_property(this, "utilsService", void 0);
|
|
55
|
-
this.utilsService = utilsService;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
Slug = _ts_decorate([
|
|
59
|
-
Injectable(),
|
|
60
|
-
_ts_param(0, Inject(UtilsService)),
|
|
61
|
-
_ts_metadata("design:type", Function),
|
|
62
|
-
_ts_metadata("design:paramtypes", [
|
|
63
|
-
typeof UtilsService === "undefined" ? Object : UtilsService
|
|
64
|
-
])
|
|
65
|
-
], Slug);
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import { of } from 'rxjs';
|
|
2
|
-
import { Slug } from './slug.interceptor';
|
|
3
|
-
function buildContext(body) {
|
|
4
|
-
const request = {
|
|
5
|
-
body
|
|
6
|
-
};
|
|
7
|
-
const context = {
|
|
8
|
-
switchToHttp: ()=>({
|
|
9
|
-
getRequest: ()=>request
|
|
10
|
-
})
|
|
11
|
-
};
|
|
12
|
-
return {
|
|
13
|
-
context,
|
|
14
|
-
request
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
function buildCallHandler() {
|
|
18
|
-
return {
|
|
19
|
-
handle: jest.fn().mockReturnValue(of('next-result'))
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
describe('Slug interceptor', ()=>{
|
|
23
|
-
let utilsService;
|
|
24
|
-
let interceptor;
|
|
25
|
-
beforeEach(()=>{
|
|
26
|
-
utilsService = {
|
|
27
|
-
transformToSlug: jest.fn((value)=>value.toLowerCase().replace(/\s+/g, '-'))
|
|
28
|
-
};
|
|
29
|
-
interceptor = new Slug(utilsService);
|
|
30
|
-
});
|
|
31
|
-
it('should generate a slug from name on a single object body without one', ()=>{
|
|
32
|
-
const { context, request } = buildContext({
|
|
33
|
-
name: 'My Product'
|
|
34
|
-
});
|
|
35
|
-
interceptor.intercept(context, buildCallHandler());
|
|
36
|
-
expect(utilsService.transformToSlug).toHaveBeenCalledWith('My Product');
|
|
37
|
-
expect(request.body).toEqual({
|
|
38
|
-
name: 'My Product',
|
|
39
|
-
slug: 'my-product'
|
|
40
|
-
});
|
|
41
|
-
});
|
|
42
|
-
it('should not overwrite an existing slug on a single object body', ()=>{
|
|
43
|
-
const { context, request } = buildContext({
|
|
44
|
-
name: 'My Product',
|
|
45
|
-
slug: 'custom-slug'
|
|
46
|
-
});
|
|
47
|
-
interceptor.intercept(context, buildCallHandler());
|
|
48
|
-
expect(utilsService.transformToSlug).not.toHaveBeenCalled();
|
|
49
|
-
expect(request.body).toEqual({
|
|
50
|
-
name: 'My Product',
|
|
51
|
-
slug: 'custom-slug'
|
|
52
|
-
});
|
|
53
|
-
});
|
|
54
|
-
it('should not generate a slug when there is no name', ()=>{
|
|
55
|
-
const { context, request } = buildContext({
|
|
56
|
-
description: 'no name here'
|
|
57
|
-
});
|
|
58
|
-
interceptor.intercept(context, buildCallHandler());
|
|
59
|
-
expect(utilsService.transformToSlug).not.toHaveBeenCalled();
|
|
60
|
-
expect(request.body).toEqual({
|
|
61
|
-
description: 'no name here'
|
|
62
|
-
});
|
|
63
|
-
});
|
|
64
|
-
it('should generate slugs for each array item missing one', ()=>{
|
|
65
|
-
const { context, request } = buildContext([
|
|
66
|
-
{
|
|
67
|
-
name: 'Item One'
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
name: 'Item Two',
|
|
71
|
-
slug: 'existing'
|
|
72
|
-
},
|
|
73
|
-
{
|
|
74
|
-
description: 'no name'
|
|
75
|
-
}
|
|
76
|
-
]);
|
|
77
|
-
interceptor.intercept(context, buildCallHandler());
|
|
78
|
-
expect(request.body).toEqual([
|
|
79
|
-
{
|
|
80
|
-
name: 'Item One',
|
|
81
|
-
slug: 'item-one'
|
|
82
|
-
},
|
|
83
|
-
{
|
|
84
|
-
name: 'Item Two',
|
|
85
|
-
slug: 'existing'
|
|
86
|
-
},
|
|
87
|
-
{
|
|
88
|
-
description: 'no name'
|
|
89
|
-
}
|
|
90
|
-
]);
|
|
91
|
-
});
|
|
92
|
-
it('should not throw when body is undefined', ()=>{
|
|
93
|
-
const { context, request } = buildContext(undefined);
|
|
94
|
-
expect(()=>interceptor.intercept(context, buildCallHandler())).not.toThrow();
|
|
95
|
-
expect(request.body).toBeUndefined();
|
|
96
|
-
});
|
|
97
|
-
it('should return next.handle() observable', (done)=>{
|
|
98
|
-
const { context } = buildContext({
|
|
99
|
-
name: 'X'
|
|
100
|
-
});
|
|
101
|
-
interceptor.intercept(context, buildCallHandler()).subscribe((value)=>{
|
|
102
|
-
expect(value).toBe('next-result');
|
|
103
|
-
done();
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export const EVENT_MANAGER_ADAPTER = 'EVENT_MANAGER_ADAPTER';
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { };
|