@dismissible/nestjs-dismissible 0.0.2-canary.c91edbc.0 → 0.0.2-canary.d2f56d7.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.
Files changed (41) hide show
  1. package/README.md +51 -67
  2. package/package.json +3 -3
  3. package/src/api/dismissible-item-response.dto.ts +0 -8
  4. package/src/api/dismissible-item.mapper.spec.ts +0 -12
  5. package/src/api/dismissible-item.mapper.ts +2 -8
  6. package/src/api/index.ts +3 -0
  7. package/src/api/use-cases/dismiss/dismiss.controller.spec.ts +1 -2
  8. package/src/api/use-cases/dismiss/dismiss.controller.ts +8 -8
  9. package/src/api/use-cases/get-or-create/get-or-create.controller.spec.ts +2 -42
  10. package/src/api/use-cases/get-or-create/get-or-create.controller.ts +10 -56
  11. package/src/api/use-cases/get-or-create/index.ts +0 -1
  12. package/src/api/use-cases/restore/restore.controller.spec.ts +1 -2
  13. package/src/api/use-cases/restore/restore.controller.ts +8 -8
  14. package/src/api/validation/index.ts +2 -0
  15. package/src/api/validation/param-validation.pipe.spec.ts +317 -0
  16. package/src/api/validation/param-validation.pipe.ts +42 -0
  17. package/src/api/validation/param.decorators.ts +32 -0
  18. package/src/core/dismissible-core.service.spec.ts +3 -45
  19. package/src/core/dismissible-core.service.ts +10 -27
  20. package/src/core/dismissible.service.spec.ts +23 -16
  21. package/src/core/dismissible.service.ts +28 -11
  22. package/src/core/hook-runner.service.spec.ts +369 -19
  23. package/src/core/hook-runner.service.ts +17 -17
  24. package/src/core/index.ts +0 -1
  25. package/src/core/lifecycle-hook.interface.ts +8 -8
  26. package/src/core/service-responses.interface.ts +9 -9
  27. package/src/dismissible.module.integration.spec.ts +685 -0
  28. package/src/dismissible.module.ts +6 -10
  29. package/src/events/dismissible.events.ts +16 -39
  30. package/src/index.ts +1 -0
  31. package/src/request/request-context.decorator.ts +1 -0
  32. package/src/request/request-context.interface.ts +6 -0
  33. package/src/response/http-exception-filter.spec.ts +213 -0
  34. package/src/testing/factories.ts +5 -8
  35. package/src/utils/dismissible.helper.ts +2 -2
  36. package/src/validation/dismissible-input.dto.ts +47 -0
  37. package/src/validation/index.ts +1 -0
  38. package/tsconfig.json +3 -0
  39. package/tsconfig.spec.json +12 -0
  40. package/src/api/use-cases/get-or-create/get-or-create.request.dto.ts +0 -17
  41. package/src/core/create-options.ts +0 -9
@@ -10,7 +10,6 @@ import { DismissibleItemMapper } from './api/dismissible-item.mapper';
10
10
  import { DateService } from './utils/date/date.service';
11
11
  import { DISMISSIBLE_HOOKS, IDismissibleLifecycleHook } from './core/lifecycle-hook.interface';
12
12
  import { LoggerModule, IDismissibleLoggerModuleOptions } from '@dismissible/nestjs-logger';
13
- import { BaseMetadata } from '@dismissible/nestjs-dismissible-item';
14
13
  import { ResponseService, ResponseModule } from './response';
15
14
  import { ValidationModule } from '@dismissible/nestjs-validation';
16
15
  import { IDismissibleStorageModuleOptions, StorageModule } from '@dismissible/nestjs-storage';
@@ -20,17 +19,14 @@ import { DismissibleItemModule } from '@dismissible/nestjs-dismissible-item';
20
19
  /**
21
20
  * Module configuration options.
22
21
  */
23
- export type IDismissibleModuleOptions<TMetadata extends BaseMetadata = BaseMetadata> =
24
- IDismissibleLoggerModuleOptions &
25
- IDismissibleStorageModuleOptions & {
26
- hooks?: Type<IDismissibleLifecycleHook<TMetadata>>[];
27
- };
22
+ export type IDismissibleModuleOptions = IDismissibleLoggerModuleOptions &
23
+ IDismissibleStorageModuleOptions & {
24
+ hooks?: Type<IDismissibleLifecycleHook>[];
25
+ };
28
26
 
29
27
  @Module({})
30
28
  export class DismissibleModule {
31
- static forRoot<TMetadata extends BaseMetadata = BaseMetadata>(
32
- options: IDismissibleModuleOptions<TMetadata>,
33
- ): DynamicModule {
29
+ static forRoot(options: IDismissibleModuleOptions): DynamicModule {
34
30
  const providers: Provider[] = [
35
31
  DateService,
36
32
  ResponseService,
@@ -48,7 +44,7 @@ export class DismissibleModule {
48
44
 
49
45
  providers.push({
50
46
  provide: DISMISSIBLE_HOOKS,
51
- useFactory: (...hooks: IDismissibleLifecycleHook<TMetadata>[]) => hooks,
47
+ useFactory: (...hooks: IDismissibleLifecycleHook[]) => hooks,
52
48
  inject: options.hooks,
53
49
  });
54
50
  } else {
@@ -1,15 +1,15 @@
1
- import { BaseMetadata, DismissibleItemDto } from '@dismissible/nestjs-dismissible-item';
1
+ import { DismissibleItemDto } from '@dismissible/nestjs-dismissible-item';
2
2
  import { IRequestContext } from '../request/request-context.interface';
3
3
 
4
4
  /**
5
5
  * Base class for all dismissible events.
6
6
  */
7
- abstract class BaseDismissibleEvent<TMetadata extends BaseMetadata = BaseMetadata> {
7
+ abstract class BaseDismissibleEvent {
8
8
  /** The item identifier */
9
9
  readonly id: string;
10
10
 
11
11
  /** The current state of the item */
12
- readonly item: DismissibleItemDto<TMetadata>;
12
+ readonly item: DismissibleItemDto;
13
13
 
14
14
  /** The user identifier */
15
15
  readonly userId: string;
@@ -17,12 +17,7 @@ abstract class BaseDismissibleEvent<TMetadata extends BaseMetadata = BaseMetadat
17
17
  /** The request context (optional) */
18
18
  readonly context?: IRequestContext;
19
19
 
20
- constructor(
21
- itemId: string,
22
- item: DismissibleItemDto<TMetadata>,
23
- userId: string,
24
- context?: IRequestContext,
25
- ) {
20
+ constructor(itemId: string, item: DismissibleItemDto, userId: string, context?: IRequestContext) {
26
21
  this.id = itemId;
27
22
  this.item = item;
28
23
  this.userId = userId;
@@ -33,15 +28,8 @@ abstract class BaseDismissibleEvent<TMetadata extends BaseMetadata = BaseMetadat
33
28
  /**
34
29
  * Event emitted when an existing item is retrieved.
35
30
  */
36
- export class ItemRetrievedEvent<
37
- TMetadata extends BaseMetadata = BaseMetadata,
38
- > extends BaseDismissibleEvent<TMetadata> {
39
- constructor(
40
- itemId: string,
41
- item: DismissibleItemDto<TMetadata>,
42
- userId: string,
43
- context?: IRequestContext,
44
- ) {
31
+ export class ItemRetrievedEvent extends BaseDismissibleEvent {
32
+ constructor(itemId: string, item: DismissibleItemDto, userId: string, context?: IRequestContext) {
45
33
  super(itemId, item, userId, context);
46
34
  }
47
35
  }
@@ -49,15 +37,8 @@ export class ItemRetrievedEvent<
49
37
  /**
50
38
  * Event emitted when a new item is created.
51
39
  */
52
- export class ItemCreatedEvent<
53
- TMetadata extends BaseMetadata = BaseMetadata,
54
- > extends BaseDismissibleEvent<TMetadata> {
55
- constructor(
56
- itemId: string,
57
- item: DismissibleItemDto<TMetadata>,
58
- userId: string,
59
- context?: IRequestContext,
60
- ) {
40
+ export class ItemCreatedEvent extends BaseDismissibleEvent {
41
+ constructor(itemId: string, item: DismissibleItemDto, userId: string, context?: IRequestContext) {
61
42
  super(itemId, item, userId, context);
62
43
  }
63
44
  }
@@ -65,16 +46,14 @@ export class ItemCreatedEvent<
65
46
  /**
66
47
  * Event emitted when an item is dismissed.
67
48
  */
68
- export class ItemDismissedEvent<
69
- TMetadata extends BaseMetadata = BaseMetadata,
70
- > extends BaseDismissibleEvent<TMetadata> {
49
+ export class ItemDismissedEvent extends BaseDismissibleEvent {
71
50
  /** The item state before dismissal */
72
- readonly previousItem: DismissibleItemDto<TMetadata>;
51
+ readonly previousItem: DismissibleItemDto;
73
52
 
74
53
  constructor(
75
54
  itemId: string,
76
- item: DismissibleItemDto<TMetadata>,
77
- previousItem: DismissibleItemDto<TMetadata>,
55
+ item: DismissibleItemDto,
56
+ previousItem: DismissibleItemDto,
78
57
  userId: string,
79
58
  context?: IRequestContext,
80
59
  ) {
@@ -86,16 +65,14 @@ export class ItemDismissedEvent<
86
65
  /**
87
66
  * Event emitted when a dismissed item is restored.
88
67
  */
89
- export class ItemRestoredEvent<
90
- TMetadata extends BaseMetadata = BaseMetadata,
91
- > extends BaseDismissibleEvent<TMetadata> {
68
+ export class ItemRestoredEvent extends BaseDismissibleEvent {
92
69
  /** The item state before restoration */
93
- readonly previousItem: DismissibleItemDto<TMetadata>;
70
+ readonly previousItem: DismissibleItemDto;
94
71
 
95
72
  constructor(
96
73
  itemId: string,
97
- item: DismissibleItemDto<TMetadata>,
98
- previousItem: DismissibleItemDto<TMetadata>,
74
+ item: DismissibleItemDto,
75
+ previousItem: DismissibleItemDto,
99
76
  userId: string,
100
77
  context?: IRequestContext,
101
78
  ) {
package/src/index.ts CHANGED
@@ -6,3 +6,4 @@ export * from './utils';
6
6
  export * from './events';
7
7
  export * from './exceptions';
8
8
  export * from './testing';
9
+ export * from './validation';
@@ -9,6 +9,7 @@ export const RequestContext = createParamDecorator(
9
9
 
10
10
  return {
11
11
  requestId: headers['x-request-id'] ?? uuidv4(),
12
+ authorizationHeader: headers['authorization'],
12
13
  };
13
14
  },
14
15
  );
@@ -3,4 +3,10 @@
3
3
  */
4
4
  export interface IRequestContext {
5
5
  requestId: string;
6
+
7
+ /**
8
+ * Authorization header value (if present).
9
+ * Used by authentication hooks.
10
+ */
11
+ authorizationHeader?: string;
6
12
  }
@@ -0,0 +1,213 @@
1
+ import { mock } from 'ts-jest-mocker';
2
+ import { HttpException, HttpStatus, ArgumentsHost } from '@nestjs/common';
3
+ import { FastifyReply } from 'fastify';
4
+ import { HttpExceptionFilter } from './http-exception-filter';
5
+
6
+ describe('HttpExceptionFilter', () => {
7
+ let filter: HttpExceptionFilter;
8
+ let mockArgumentsHost: jest.Mocked<ArgumentsHost>;
9
+ let mockHttpArgumentsHost: {
10
+ getResponse: jest.Mock;
11
+ getRequest: jest.Mock;
12
+ getNext: jest.Mock;
13
+ };
14
+ let mockResponse: jest.Mocked<FastifyReply>;
15
+
16
+ beforeEach(() => {
17
+ filter = new HttpExceptionFilter();
18
+
19
+ // Mock FastifyReply using ts-jest-mocker
20
+ mockResponse = mock<FastifyReply>({ failIfMockNotProvided: false });
21
+ mockResponse.status = jest.fn().mockReturnThis();
22
+ mockResponse.send = jest.fn().mockReturnThis();
23
+
24
+ // Mock HTTP arguments host
25
+ mockHttpArgumentsHost = {
26
+ getResponse: jest.fn().mockReturnValue(mockResponse),
27
+ getRequest: jest.fn(),
28
+ getNext: jest.fn(),
29
+ };
30
+
31
+ // Mock ArgumentsHost using ts-jest-mocker
32
+ mockArgumentsHost = mock<ArgumentsHost>({ failIfMockNotProvided: false });
33
+ mockArgumentsHost.switchToHttp = jest.fn().mockReturnValue(mockHttpArgumentsHost);
34
+ });
35
+
36
+ afterEach(() => {
37
+ jest.clearAllMocks();
38
+ });
39
+
40
+ describe('catch', () => {
41
+ it('should handle HttpException with 404 status', () => {
42
+ // Arrange
43
+ const exception = new HttpException('Not found', HttpStatus.NOT_FOUND);
44
+
45
+ // Act
46
+ filter.catch(exception, mockArgumentsHost);
47
+
48
+ // Assert
49
+ expect(mockArgumentsHost.switchToHttp).toHaveBeenCalled();
50
+ expect(mockHttpArgumentsHost.getResponse).toHaveBeenCalled();
51
+ expect(mockResponse.status).toHaveBeenCalledWith(404);
52
+ expect(mockResponse.send).toHaveBeenCalledWith({
53
+ error: {
54
+ message: 'Not found',
55
+ code: 404,
56
+ },
57
+ });
58
+ });
59
+
60
+ it('should handle HttpException with 400 status', () => {
61
+ // Arrange
62
+ const exception = new HttpException('Bad request', HttpStatus.BAD_REQUEST);
63
+
64
+ // Act
65
+ filter.catch(exception, mockArgumentsHost);
66
+
67
+ // Assert
68
+ expect(mockResponse.status).toHaveBeenCalledWith(400);
69
+ expect(mockResponse.send).toHaveBeenCalledWith({
70
+ error: {
71
+ message: 'Bad request',
72
+ code: 400,
73
+ },
74
+ });
75
+ });
76
+
77
+ it('should handle HttpException with 401 status', () => {
78
+ // Arrange
79
+ const exception = new HttpException('Unauthorized', HttpStatus.UNAUTHORIZED);
80
+
81
+ // Act
82
+ filter.catch(exception, mockArgumentsHost);
83
+
84
+ // Assert
85
+ expect(mockResponse.status).toHaveBeenCalledWith(401);
86
+ expect(mockResponse.send).toHaveBeenCalledWith({
87
+ error: {
88
+ message: 'Unauthorized',
89
+ code: 401,
90
+ },
91
+ });
92
+ });
93
+
94
+ it('should handle HttpException with 403 status', () => {
95
+ // Arrange
96
+ const exception = new HttpException('Forbidden', HttpStatus.FORBIDDEN);
97
+
98
+ // Act
99
+ filter.catch(exception, mockArgumentsHost);
100
+
101
+ // Assert
102
+ expect(mockResponse.status).toHaveBeenCalledWith(403);
103
+ expect(mockResponse.send).toHaveBeenCalledWith({
104
+ error: {
105
+ message: 'Forbidden',
106
+ code: 403,
107
+ },
108
+ });
109
+ });
110
+
111
+ it('should handle HttpException with 500 status', () => {
112
+ // Arrange
113
+ const exception = new HttpException(
114
+ 'Internal server error',
115
+ HttpStatus.INTERNAL_SERVER_ERROR,
116
+ );
117
+
118
+ // Act
119
+ filter.catch(exception, mockArgumentsHost);
120
+
121
+ // Assert
122
+ expect(mockResponse.status).toHaveBeenCalledWith(500);
123
+ expect(mockResponse.send).toHaveBeenCalledWith({
124
+ error: {
125
+ message: 'Internal server error',
126
+ code: 500,
127
+ },
128
+ });
129
+ });
130
+
131
+ it('should handle HttpException with custom status code', () => {
132
+ // Arrange
133
+ const exception = new HttpException('Custom error', 418);
134
+
135
+ // Act
136
+ filter.catch(exception, mockArgumentsHost);
137
+
138
+ // Assert
139
+ expect(mockResponse.status).toHaveBeenCalledWith(418);
140
+ expect(mockResponse.send).toHaveBeenCalledWith({
141
+ error: {
142
+ message: 'Custom error',
143
+ code: 418,
144
+ },
145
+ });
146
+ });
147
+
148
+ it('should handle HttpException with empty message', () => {
149
+ // Arrange
150
+ const exception = new HttpException('', HttpStatus.BAD_REQUEST);
151
+
152
+ // Act
153
+ filter.catch(exception, mockArgumentsHost);
154
+
155
+ // Assert
156
+ expect(mockResponse.status).toHaveBeenCalledWith(400);
157
+ expect(mockResponse.send).toHaveBeenCalledWith({
158
+ error: {
159
+ message: '',
160
+ code: 400,
161
+ },
162
+ });
163
+ });
164
+
165
+ it('should handle HttpException with long message', () => {
166
+ // Arrange
167
+ const longMessage =
168
+ 'This is a very long error message that contains multiple words and should be handled correctly by the filter';
169
+ const exception = new HttpException(longMessage, HttpStatus.BAD_REQUEST);
170
+
171
+ // Act
172
+ filter.catch(exception, mockArgumentsHost);
173
+
174
+ // Assert
175
+ expect(mockResponse.status).toHaveBeenCalledWith(400);
176
+ expect(mockResponse.send).toHaveBeenCalledWith({
177
+ error: {
178
+ message: longMessage,
179
+ code: 400,
180
+ },
181
+ });
182
+ });
183
+
184
+ it('should chain status and send methods correctly', () => {
185
+ // Arrange
186
+ const exception = new HttpException('Test error', HttpStatus.NOT_FOUND);
187
+
188
+ // Act
189
+ filter.catch(exception, mockArgumentsHost);
190
+
191
+ // Assert
192
+ expect(mockResponse.status).toHaveBeenCalled();
193
+ expect(mockResponse.send).toHaveBeenCalled();
194
+ expect(mockResponse.status).toHaveReturnedWith(mockResponse);
195
+ // Verify status is called before send by checking call order
196
+ const statusCallOrder = (mockResponse.status as jest.Mock).mock.invocationCallOrder[0];
197
+ const sendCallOrder = (mockResponse.send as jest.Mock).mock.invocationCallOrder[0];
198
+ expect(statusCallOrder).toBeLessThan(sendCallOrder);
199
+ });
200
+
201
+ it('should extract response from HTTP context correctly', () => {
202
+ // Arrange
203
+ const exception = new HttpException('Test', HttpStatus.BAD_REQUEST);
204
+
205
+ // Act
206
+ filter.catch(exception, mockArgumentsHost);
207
+
208
+ // Assert
209
+ expect(mockArgumentsHost.switchToHttp).toHaveBeenCalledTimes(1);
210
+ expect(mockHttpArgumentsHost.getResponse).toHaveBeenCalledTimes(1);
211
+ });
212
+ });
213
+ });
@@ -1,4 +1,4 @@
1
- import { BaseMetadata, DismissibleItemDto } from '@dismissible/nestjs-dismissible-item';
1
+ import { DismissibleItemDto } from '@dismissible/nestjs-dismissible-item';
2
2
  import { DismissibleItemFactory } from '@dismissible/nestjs-dismissible-item';
3
3
  import { IRequestContext } from '../request/request-context.interface';
4
4
 
@@ -10,14 +10,11 @@ const testItemFactory = new DismissibleItemFactory();
10
10
  /**
11
11
  * Create a test dismissible item.
12
12
  */
13
- export function createTestItem<TMetadata extends BaseMetadata = BaseMetadata>(
14
- overrides: Partial<DismissibleItemDto<TMetadata>> = {},
15
- ): DismissibleItemDto<TMetadata> {
13
+ export function createTestItem(overrides: Partial<DismissibleItemDto> = {}): DismissibleItemDto {
16
14
  return testItemFactory.create({
17
15
  id: overrides.id ?? 'test-item-id',
18
16
  createdAt: overrides.createdAt ?? new Date('2024-01-15T10:00:00.000Z'),
19
17
  userId: overrides.userId ?? 'test-user-id',
20
- metadata: overrides.metadata,
21
18
  dismissedAt: overrides.dismissedAt,
22
19
  });
23
20
  }
@@ -35,9 +32,9 @@ export function createTestContext(overrides: Partial<IRequestContext> = {}): IRe
35
32
  /**
36
33
  * Create a dismissed test item.
37
34
  */
38
- export function createDismissedTestItem<TMetadata extends BaseMetadata = BaseMetadata>(
39
- overrides: Partial<DismissibleItemDto<TMetadata>> = {},
40
- ): DismissibleItemDto<TMetadata> {
35
+ export function createDismissedTestItem(
36
+ overrides: Partial<DismissibleItemDto> = {},
37
+ ): DismissibleItemDto {
41
38
  return createTestItem({
42
39
  dismissedAt: new Date('2024-01-15T12:00:00.000Z'),
43
40
  ...overrides,
@@ -1,9 +1,9 @@
1
1
  import { Injectable } from '@nestjs/common';
2
- import { BaseMetadata, DismissibleItemDto } from '@dismissible/nestjs-dismissible-item';
2
+ import { DismissibleItemDto } from '@dismissible/nestjs-dismissible-item';
3
3
 
4
4
  @Injectable()
5
5
  export class DismissibleHelper {
6
- isDismissed<TMetadata extends BaseMetadata>(item: DismissibleItemDto<TMetadata>): boolean {
6
+ isDismissed(item: DismissibleItemDto): boolean {
7
7
  return item.dismissedAt !== undefined && item.dismissedAt !== null;
8
8
  }
9
9
  }
@@ -0,0 +1,47 @@
1
+ import { IsNotEmpty, IsString, Matches, MaxLength, MinLength } from 'class-validator';
2
+
3
+ /**
4
+ * Validation constants for dismissible input fields.
5
+ */
6
+ export const VALIDATION_CONSTANTS = {
7
+ /** Maximum length for userId and itemId */
8
+ ID_MAX_LENGTH: 64,
9
+ /** Minimum length for userId and itemId */
10
+ ID_MIN_LENGTH: 1,
11
+ /** Pattern for valid userId and itemId (alphanumeric, dash, underscore) */
12
+ ID_PATTERN: /^[a-zA-Z0-9_-]+$/,
13
+ /** Human-readable description of the ID pattern */
14
+ ID_PATTERN_MESSAGE: 'must contain only alphanumeric characters, dashes, and underscores',
15
+ } as const;
16
+
17
+ /**
18
+ * DTO for validating dismissible input parameters (userId and itemId).
19
+ * Used at both controller and service layers for defense in depth.
20
+ */
21
+ export class DismissibleInputDto {
22
+ @IsString()
23
+ @IsNotEmpty({ message: 'itemId is required' })
24
+ @MinLength(VALIDATION_CONSTANTS.ID_MIN_LENGTH, {
25
+ message: `itemId must be at least ${VALIDATION_CONSTANTS.ID_MIN_LENGTH} character`,
26
+ })
27
+ @MaxLength(VALIDATION_CONSTANTS.ID_MAX_LENGTH, {
28
+ message: `itemId must be at most ${VALIDATION_CONSTANTS.ID_MAX_LENGTH} characters`,
29
+ })
30
+ @Matches(VALIDATION_CONSTANTS.ID_PATTERN, {
31
+ message: `itemId ${VALIDATION_CONSTANTS.ID_PATTERN_MESSAGE}`,
32
+ })
33
+ itemId: string;
34
+
35
+ @IsString()
36
+ @IsNotEmpty({ message: 'userId is required' })
37
+ @MinLength(VALIDATION_CONSTANTS.ID_MIN_LENGTH, {
38
+ message: `userId must be at least ${VALIDATION_CONSTANTS.ID_MIN_LENGTH} character`,
39
+ })
40
+ @MaxLength(VALIDATION_CONSTANTS.ID_MAX_LENGTH, {
41
+ message: `userId must be at most ${VALIDATION_CONSTANTS.ID_MAX_LENGTH} characters`,
42
+ })
43
+ @Matches(VALIDATION_CONSTANTS.ID_PATTERN, {
44
+ message: `userId ${VALIDATION_CONSTANTS.ID_PATTERN_MESSAGE}`,
45
+ })
46
+ userId: string;
47
+ }
@@ -0,0 +1 @@
1
+ export * from './dismissible-input.dto';
package/tsconfig.json CHANGED
@@ -5,6 +5,9 @@
5
5
  "references": [
6
6
  {
7
7
  "path": "./tsconfig.lib.json"
8
+ },
9
+ {
10
+ "path": "./tsconfig.spec.json"
8
11
  }
9
12
  ],
10
13
  "compilerOptions": {
@@ -0,0 +1,12 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "../../dist/out-tsc",
5
+ "module": "commonjs",
6
+ "types": ["node", "jest"],
7
+ "emitDecoratorMetadata": true,
8
+ "experimentalDecorators": true,
9
+ "target": "ES2021"
10
+ },
11
+ "include": ["src/**/*.spec.ts", "src/**/*.test.ts"]
12
+ }
@@ -1,17 +0,0 @@
1
- import { ApiPropertyOptional } from '@nestjs/swagger';
2
- import { IsOptional, IsObject } from 'class-validator';
3
-
4
- /**
5
- * Query parameters for creating a dismissible item.
6
- */
7
- export class CreateDismissibleItemQueryDto {
8
- @ApiPropertyOptional({
9
- description: 'Optional metadata to attach to the item',
10
- example: { key: 'value' },
11
- type: 'object',
12
- additionalProperties: true,
13
- })
14
- @IsOptional()
15
- @IsObject()
16
- metadata?: Record<string, string | number>;
17
- }
@@ -1,9 +0,0 @@
1
- import { BaseMetadata } from '@dismissible/nestjs-dismissible-item';
2
-
3
- /**
4
- * Options for creating a new dismissible item.
5
- */
6
- export interface ICreateItemOptions<TMetadata extends BaseMetadata = BaseMetadata> {
7
- /** Optional metadata to attach to the item */
8
- metadata?: TMetadata;
9
- }