@flusys/nestjs-form-builder 6.4.0 → 7.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.
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Domain event actions published by the form builder module, alongside the
3
+ * CRUD lifecycle actions every ApiService emits.
4
+ */ "use strict";
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ function _export(target, all) {
9
+ for(var name in all)Object.defineProperty(target, name, {
10
+ enumerable: true,
11
+ get: Object.getOwnPropertyDescriptor(all, name).get
12
+ });
13
+ }
14
+ _export(exports, {
15
+ get FORM_BUILDER_EVENT_ACTIONS () {
16
+ return FORM_BUILDER_EVENT_ACTIONS;
17
+ },
18
+ get FORM_BUILDER_EVENT_ENTITIES () {
19
+ return FORM_BUILDER_EVENT_ENTITIES;
20
+ }
21
+ });
22
+ const FORM_BUILDER_EVENT_ACTIONS = {
23
+ SUBMITTED: 'submitted',
24
+ DRAFT_SAVED: 'draft-saved'
25
+ };
26
+ const FORM_BUILDER_EVENT_ENTITIES = {
27
+ FORM: 'form',
28
+ FORM_RESULT: 'form_result'
29
+ };
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", {
3
3
  value: true
4
4
  });
5
+ _export_star(require("./event-actions"), exports);
5
6
  _export_star(require("./form-builder.constants"), exports);
6
7
  _export_star(require("./message-keys"), exports);
7
8
  function _export_star(from, to) {
@@ -80,6 +80,7 @@ let FormBuilderModule = class FormBuilderModule {
80
80
  useValue: options
81
81
  });
82
82
  }
83
+ providers.push((0, _modules.createModuleEventsProvider)('form-builder', _formbuilderconstants.FORM_BUILDER_MODULE_OPTIONS));
83
84
  return providers;
84
85
  }
85
86
  static buildAsyncProviders(options) {
@@ -189,6 +189,7 @@ let FormResultService = class FormResultService extends _classes.ApiService {
189
189
  const form = await this.getActiveForm(dto.formId);
190
190
  await this.validateSubmissionAccess(form, user, isPublic);
191
191
  const isDraft = dto.isDraft ?? false;
192
+ const staleResults = [];
192
193
  // Handle existing draft for authenticated users
193
194
  if (user?.id) {
194
195
  const existingDraft = await this.repository.findOne({
@@ -203,9 +204,14 @@ let FormResultService = class FormResultService extends _classes.ApiService {
203
204
  submittedAt: new Date()
204
205
  });
205
206
  const saved = await this.repository.save(existingDraft);
207
+ await this.invalidateResultCache([
208
+ saved
209
+ ]);
210
+ await this.publishSubmissionEvent(saved, dto.formId, true, user);
206
211
  return this.convertEntityToResponseDto(saved, false);
207
212
  }
208
213
  await this.repository.softRemove(existingDraft);
214
+ staleResults.push(existingDraft);
209
215
  }
210
216
  }
211
217
  const saved = await this.repository.save({
@@ -217,6 +223,11 @@ let FormResultService = class FormResultService extends _classes.ApiService {
217
223
  submittedAt: new Date(),
218
224
  isDraft
219
225
  });
226
+ await this.invalidateResultCache([
227
+ ...staleResults,
228
+ saved
229
+ ]);
230
+ await this.publishSubmissionEvent(saved, dto.formId, isDraft, user);
220
231
  return this.convertEntityToResponseDto(saved, false);
221
232
  }
222
233
  async getMyDraft(formId, user) {
@@ -254,8 +265,32 @@ let FormResultService = class FormResultService extends _classes.ApiService {
254
265
  isDraft
255
266
  });
256
267
  const saved = await this.repository.save(draft);
268
+ await this.invalidateResultCache([
269
+ saved
270
+ ]);
271
+ await this.publishSubmissionEvent(saved, dto.formId, isDraft, user);
257
272
  return this.convertEntityToResponseDto(saved, false);
258
273
  }
274
+ async publishSubmissionEvent(result, formId, isDraft, user) {
275
+ await this.publishDomainAction(isDraft ? _config.FORM_BUILDER_EVENT_ACTIONS.DRAFT_SAVED : _config.FORM_BUILDER_EVENT_ACTIONS.SUBMITTED, {
276
+ ids: [
277
+ result.id
278
+ ],
279
+ data: result,
280
+ metadata: {
281
+ formId,
282
+ isDraft,
283
+ schemaVersion: result.schemaVersion
284
+ },
285
+ user
286
+ });
287
+ }
288
+ async invalidateResultCache(results) {
289
+ await Promise.all([
290
+ this.clearCacheForAll(),
291
+ this.clearCacheForId(results)
292
+ ]);
293
+ }
259
294
  async getByFormId(formId, user, pagination) {
260
295
  await this.ensureDataSourceRepository();
261
296
  const query = this.repository.createQueryBuilder(this.entityName).where('form_result.formId = :formId', {
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", {
3
3
  value: true
4
4
  });
5
5
  const _testing = require("@nestjs/testing");
6
+ const _classes = require("@flusys/nestjs-shared/classes");
6
7
  const _modules = require("@flusys/nestjs-shared/modules");
7
8
  const _repositorymock = require("@test-utils/mocks/repository.mock");
8
9
  const _loggedusermock = require("@test-utils/mocks/logged-user.mock");
@@ -108,6 +109,15 @@ describe('FormResultService', ()=>{
108
109
  let mockResultRepo;
109
110
  let mockFormRepo;
110
111
  let mockFormBuilderConfig;
112
+ const mockUtilsService = {
113
+ clearCache: jest.fn(),
114
+ getCacheKey: jest.fn().mockReturnValue('cache-key'),
115
+ trackCacheKey: jest.fn()
116
+ };
117
+ // Call history is shared across tests in this file; reset it so each cache assertion is exact.
118
+ beforeEach(()=>{
119
+ mockUtilsService.clearCache.mockClear();
120
+ });
111
121
  async function buildService(companyFeatureEnabled = false) {
112
122
  mockResultRepo = (0, _repositorymock.createMockRepository)();
113
123
  mockFormRepo = (0, _repositorymock.createMockRepository)();
@@ -138,7 +148,7 @@ describe('FormResultService', ()=>{
138
148
  },
139
149
  {
140
150
  provide: _modules.UtilsService,
141
- useValue: {}
151
+ useValue: mockUtilsService
142
152
  },
143
153
  {
144
154
  provide: _formbuilderconfigservice.FormBuilderConfigService,
@@ -417,6 +427,43 @@ describe('FormResultService', ()=>{
417
427
  isDraft: false
418
428
  }));
419
429
  });
430
+ it('invalidates the result list cache and the new entry after a submission', async ()=>{
431
+ await buildService(false);
432
+ mockFormRepo.findOne.mockResolvedValue(buildForm());
433
+ mockResultRepo.findOne.mockResolvedValue(null);
434
+ mockResultRepo.save.mockResolvedValue(buildFormResult({
435
+ id: 'result-1'
436
+ }));
437
+ await service.submitForm({
438
+ formId: 'form-uuid-1',
439
+ data: {
440
+ field1: 'x'
441
+ }
442
+ }, (0, _loggedusermock.buildMockUser)(), false);
443
+ expect(mockUtilsService.clearCache).toHaveBeenCalledWith('form_result', expect.anything());
444
+ expect(mockUtilsService.clearCache).toHaveBeenCalledWith('form_result', expect.anything(), 'result-1');
445
+ });
446
+ it('invalidates the soft-removed draft as well when a draft is finalized into a new record', async ()=>{
447
+ await buildService(false);
448
+ mockFormRepo.findOne.mockResolvedValue(buildForm());
449
+ mockResultRepo.findOne.mockResolvedValue(buildFormResult({
450
+ id: 'draft-1',
451
+ isDraft: true
452
+ }));
453
+ mockResultRepo.save.mockResolvedValue(buildFormResult({
454
+ id: 'result-2'
455
+ }));
456
+ await service.submitForm({
457
+ formId: 'form-uuid-1',
458
+ data: {
459
+ field1: 'x'
460
+ },
461
+ isDraft: false
462
+ }, (0, _loggedusermock.buildMockUser)(), false);
463
+ expect(mockResultRepo.softRemove).toHaveBeenCalled();
464
+ expect(mockUtilsService.clearCache).toHaveBeenCalledWith('form_result', expect.anything(), 'draft-1');
465
+ expect(mockUtilsService.clearCache).toHaveBeenCalledWith('form_result', expect.anything(), 'result-2');
466
+ });
420
467
  it('does not compute fields when saving as a draft', async ()=>{
421
468
  await buildService(false);
422
469
  const form = buildForm({
@@ -699,4 +746,78 @@ describe('FormResultService', ()=>{
699
746
  expect(result).toBe(false);
700
747
  });
701
748
  });
749
+ describe('domain events', ()=>{
750
+ let publish;
751
+ beforeEach(()=>{
752
+ publish = jest.fn().mockResolvedValue(undefined);
753
+ _classes.EventBusRegistry.reset();
754
+ _classes.EventBusRegistry.setBus({
755
+ publish,
756
+ subscribe: jest.fn(),
757
+ close: jest.fn()
758
+ });
759
+ _classes.EventBusRegistry.configureModule('form-builder', {
760
+ enabled: true
761
+ });
762
+ });
763
+ afterEach(()=>{
764
+ _classes.EventBusRegistry.reset();
765
+ });
766
+ it('publishes form-builder.form_result.submitted for a final submission', async ()=>{
767
+ await buildService(false);
768
+ mockFormRepo.findOne.mockResolvedValue(buildForm({
769
+ accessType: _formaccesstypeenum.FormAccessType.PUBLIC
770
+ }));
771
+ mockResultRepo.save.mockResolvedValue(buildFormResult({
772
+ isDraft: false
773
+ }));
774
+ await service.submitForm({
775
+ formId: 'form-uuid-1',
776
+ data: {}
777
+ }, null, true);
778
+ expect(publish).toHaveBeenCalledWith(expect.objectContaining({
779
+ name: 'form-builder.form_result.submitted',
780
+ action: 'submitted',
781
+ payload: expect.objectContaining({
782
+ ids: [
783
+ 'result-uuid-1'
784
+ ],
785
+ metadata: expect.objectContaining({
786
+ formId: 'form-uuid-1',
787
+ isDraft: false
788
+ })
789
+ })
790
+ }));
791
+ });
792
+ it('publishes form-builder.form_result.draft-saved when the submission is a draft', async ()=>{
793
+ await buildService(false);
794
+ mockFormRepo.findOne.mockResolvedValue(buildForm({
795
+ accessType: _formaccesstypeenum.FormAccessType.PUBLIC
796
+ }));
797
+ mockResultRepo.save.mockResolvedValue(buildFormResult({
798
+ isDraft: true
799
+ }));
800
+ await service.submitForm({
801
+ formId: 'form-uuid-1',
802
+ data: {},
803
+ isDraft: true
804
+ }, null, true);
805
+ expect(publish.mock.calls[0][0].name).toBe('form-builder.form_result.draft-saved');
806
+ });
807
+ it('does not publish when the module has events disabled', async ()=>{
808
+ _classes.EventBusRegistry.configureModule('form-builder', {
809
+ enabled: false
810
+ });
811
+ await buildService(false);
812
+ mockFormRepo.findOne.mockResolvedValue(buildForm({
813
+ accessType: _formaccesstypeenum.FormAccessType.PUBLIC
814
+ }));
815
+ mockResultRepo.save.mockResolvedValue(buildFormResult());
816
+ await service.submitForm({
817
+ formId: 'form-uuid-1',
818
+ data: {}
819
+ }, null, true);
820
+ expect(publish).not.toHaveBeenCalled();
821
+ });
822
+ });
702
823
  });
@@ -0,0 +1,8 @@
1
+ export declare const FORM_BUILDER_EVENT_ACTIONS: {
2
+ readonly SUBMITTED: "submitted";
3
+ readonly DRAFT_SAVED: "draft-saved";
4
+ };
5
+ export declare const FORM_BUILDER_EVENT_ENTITIES: {
6
+ readonly FORM: "form";
7
+ readonly FORM_RESULT: "form_result";
8
+ };
package/config/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
+ export * from './event-actions';
1
2
  export * from './form-builder.constants';
2
3
  export * from './message-keys';
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Domain event actions published by the form builder module, alongside the
3
+ * CRUD lifecycle actions every ApiService emits.
4
+ */ export const FORM_BUILDER_EVENT_ACTIONS = {
5
+ SUBMITTED: 'submitted',
6
+ DRAFT_SAVED: 'draft-saved'
7
+ };
8
+ /** Every entity the form builder module publishes under */ export const FORM_BUILDER_EVENT_ENTITIES = {
9
+ FORM: 'form',
10
+ FORM_RESULT: 'form_result'
11
+ };
@@ -1,2 +1,3 @@
1
+ export * from './event-actions';
1
2
  export * from './form-builder.constants';
2
3
  export * from './message-keys';
@@ -17,7 +17,7 @@ function _ts_decorate(decorators, target, key, desc) {
17
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
18
  return c > 3 && r && Object.defineProperty(target, key, r), r;
19
19
  }
20
- import { CacheModule, UtilsModule } from '@flusys/nestjs-shared/modules';
20
+ import { CacheModule, UtilsModule, createModuleEventsProvider } from '@flusys/nestjs-shared/modules';
21
21
  import { Module } from '@nestjs/common';
22
22
  import { FORM_BUILDER_MODULE_OPTIONS } from '../config/form-builder.constants';
23
23
  import { FormController, FormResultController } from '../controllers';
@@ -70,6 +70,7 @@ export class FormBuilderModule {
70
70
  useValue: options
71
71
  });
72
72
  }
73
+ providers.push(createModuleEventsProvider('form-builder', FORM_BUILDER_MODULE_OPTIONS));
73
74
  return providers;
74
75
  }
75
76
  static buildAsyncProviders(options) {
@@ -31,7 +31,7 @@ import { ILoggedUserInfo } from '@flusys/nestjs-shared/interfaces';
31
31
  import { UtilsService } from '@flusys/nestjs-shared/modules';
32
32
  import { BadRequestException, ForbiddenException, Inject, Injectable, NotFoundException, Scope, UnauthorizedException } from '@nestjs/common';
33
33
  import { IsNull } from 'typeorm';
34
- import { FORM_MESSAGES, FORM_RESULT_MESSAGES } from '../config';
34
+ import { FORM_BUILDER_EVENT_ACTIONS, FORM_MESSAGES, FORM_RESULT_MESSAGES } from '../config';
35
35
  import { SubmitFormDto } from '../dtos/form-result.dto';
36
36
  import { Form, FormResult, FormWithCompany } from '../entities';
37
37
  import { FormAccessType } from '../enums/form-access-type.enum';
@@ -179,6 +179,7 @@ export class FormResultService extends ApiService {
179
179
  const form = await this.getActiveForm(dto.formId);
180
180
  await this.validateSubmissionAccess(form, user, isPublic);
181
181
  const isDraft = dto.isDraft ?? false;
182
+ const staleResults = [];
182
183
  // Handle existing draft for authenticated users
183
184
  if (user?.id) {
184
185
  const existingDraft = await this.repository.findOne({
@@ -193,9 +194,14 @@ export class FormResultService extends ApiService {
193
194
  submittedAt: new Date()
194
195
  });
195
196
  const saved = await this.repository.save(existingDraft);
197
+ await this.invalidateResultCache([
198
+ saved
199
+ ]);
200
+ await this.publishSubmissionEvent(saved, dto.formId, true, user);
196
201
  return this.convertEntityToResponseDto(saved, false);
197
202
  }
198
203
  await this.repository.softRemove(existingDraft);
204
+ staleResults.push(existingDraft);
199
205
  }
200
206
  }
201
207
  const saved = await this.repository.save({
@@ -207,6 +213,11 @@ export class FormResultService extends ApiService {
207
213
  submittedAt: new Date(),
208
214
  isDraft
209
215
  });
216
+ await this.invalidateResultCache([
217
+ ...staleResults,
218
+ saved
219
+ ]);
220
+ await this.publishSubmissionEvent(saved, dto.formId, isDraft, user);
210
221
  return this.convertEntityToResponseDto(saved, false);
211
222
  }
212
223
  async getMyDraft(formId, user) {
@@ -244,8 +255,32 @@ export class FormResultService extends ApiService {
244
255
  isDraft
245
256
  });
246
257
  const saved = await this.repository.save(draft);
258
+ await this.invalidateResultCache([
259
+ saved
260
+ ]);
261
+ await this.publishSubmissionEvent(saved, dto.formId, isDraft, user);
247
262
  return this.convertEntityToResponseDto(saved, false);
248
263
  }
264
+ async publishSubmissionEvent(result, formId, isDraft, user) {
265
+ await this.publishDomainAction(isDraft ? FORM_BUILDER_EVENT_ACTIONS.DRAFT_SAVED : FORM_BUILDER_EVENT_ACTIONS.SUBMITTED, {
266
+ ids: [
267
+ result.id
268
+ ],
269
+ data: result,
270
+ metadata: {
271
+ formId,
272
+ isDraft,
273
+ schemaVersion: result.schemaVersion
274
+ },
275
+ user
276
+ });
277
+ }
278
+ async invalidateResultCache(results) {
279
+ await Promise.all([
280
+ this.clearCacheForAll(),
281
+ this.clearCacheForId(results)
282
+ ]);
283
+ }
249
284
  async getByFormId(formId, user, pagination) {
250
285
  await this.ensureDataSourceRepository();
251
286
  const query = this.repository.createQueryBuilder(this.entityName).where('form_result.formId = :formId', {
@@ -1,4 +1,5 @@
1
1
  import { Test } from '@nestjs/testing';
2
+ import { EventBusRegistry } from '@flusys/nestjs-shared/classes';
2
3
  import { UtilsService } from '@flusys/nestjs-shared/modules';
3
4
  import { createMockQueryBuilder, createMockRepository } from '@test-utils/mocks/repository.mock';
4
5
  import { buildMockUser } from '@test-utils/mocks/logged-user.mock';
@@ -63,6 +64,15 @@ describe('FormResultService', ()=>{
63
64
  let mockResultRepo;
64
65
  let mockFormRepo;
65
66
  let mockFormBuilderConfig;
67
+ const mockUtilsService = {
68
+ clearCache: jest.fn(),
69
+ getCacheKey: jest.fn().mockReturnValue('cache-key'),
70
+ trackCacheKey: jest.fn()
71
+ };
72
+ // Call history is shared across tests in this file; reset it so each cache assertion is exact.
73
+ beforeEach(()=>{
74
+ mockUtilsService.clearCache.mockClear();
75
+ });
66
76
  async function buildService(companyFeatureEnabled = false) {
67
77
  mockResultRepo = createMockRepository();
68
78
  mockFormRepo = createMockRepository();
@@ -93,7 +103,7 @@ describe('FormResultService', ()=>{
93
103
  },
94
104
  {
95
105
  provide: UtilsService,
96
- useValue: {}
106
+ useValue: mockUtilsService
97
107
  },
98
108
  {
99
109
  provide: FormBuilderConfigService,
@@ -372,6 +382,43 @@ describe('FormResultService', ()=>{
372
382
  isDraft: false
373
383
  }));
374
384
  });
385
+ it('invalidates the result list cache and the new entry after a submission', async ()=>{
386
+ await buildService(false);
387
+ mockFormRepo.findOne.mockResolvedValue(buildForm());
388
+ mockResultRepo.findOne.mockResolvedValue(null);
389
+ mockResultRepo.save.mockResolvedValue(buildFormResult({
390
+ id: 'result-1'
391
+ }));
392
+ await service.submitForm({
393
+ formId: 'form-uuid-1',
394
+ data: {
395
+ field1: 'x'
396
+ }
397
+ }, buildMockUser(), false);
398
+ expect(mockUtilsService.clearCache).toHaveBeenCalledWith('form_result', expect.anything());
399
+ expect(mockUtilsService.clearCache).toHaveBeenCalledWith('form_result', expect.anything(), 'result-1');
400
+ });
401
+ it('invalidates the soft-removed draft as well when a draft is finalized into a new record', async ()=>{
402
+ await buildService(false);
403
+ mockFormRepo.findOne.mockResolvedValue(buildForm());
404
+ mockResultRepo.findOne.mockResolvedValue(buildFormResult({
405
+ id: 'draft-1',
406
+ isDraft: true
407
+ }));
408
+ mockResultRepo.save.mockResolvedValue(buildFormResult({
409
+ id: 'result-2'
410
+ }));
411
+ await service.submitForm({
412
+ formId: 'form-uuid-1',
413
+ data: {
414
+ field1: 'x'
415
+ },
416
+ isDraft: false
417
+ }, buildMockUser(), false);
418
+ expect(mockResultRepo.softRemove).toHaveBeenCalled();
419
+ expect(mockUtilsService.clearCache).toHaveBeenCalledWith('form_result', expect.anything(), 'draft-1');
420
+ expect(mockUtilsService.clearCache).toHaveBeenCalledWith('form_result', expect.anything(), 'result-2');
421
+ });
375
422
  it('does not compute fields when saving as a draft', async ()=>{
376
423
  await buildService(false);
377
424
  const form = buildForm({
@@ -654,4 +701,78 @@ describe('FormResultService', ()=>{
654
701
  expect(result).toBe(false);
655
702
  });
656
703
  });
704
+ describe('domain events', ()=>{
705
+ let publish;
706
+ beforeEach(()=>{
707
+ publish = jest.fn().mockResolvedValue(undefined);
708
+ EventBusRegistry.reset();
709
+ EventBusRegistry.setBus({
710
+ publish,
711
+ subscribe: jest.fn(),
712
+ close: jest.fn()
713
+ });
714
+ EventBusRegistry.configureModule('form-builder', {
715
+ enabled: true
716
+ });
717
+ });
718
+ afterEach(()=>{
719
+ EventBusRegistry.reset();
720
+ });
721
+ it('publishes form-builder.form_result.submitted for a final submission', async ()=>{
722
+ await buildService(false);
723
+ mockFormRepo.findOne.mockResolvedValue(buildForm({
724
+ accessType: FormAccessType.PUBLIC
725
+ }));
726
+ mockResultRepo.save.mockResolvedValue(buildFormResult({
727
+ isDraft: false
728
+ }));
729
+ await service.submitForm({
730
+ formId: 'form-uuid-1',
731
+ data: {}
732
+ }, null, true);
733
+ expect(publish).toHaveBeenCalledWith(expect.objectContaining({
734
+ name: 'form-builder.form_result.submitted',
735
+ action: 'submitted',
736
+ payload: expect.objectContaining({
737
+ ids: [
738
+ 'result-uuid-1'
739
+ ],
740
+ metadata: expect.objectContaining({
741
+ formId: 'form-uuid-1',
742
+ isDraft: false
743
+ })
744
+ })
745
+ }));
746
+ });
747
+ it('publishes form-builder.form_result.draft-saved when the submission is a draft', async ()=>{
748
+ await buildService(false);
749
+ mockFormRepo.findOne.mockResolvedValue(buildForm({
750
+ accessType: FormAccessType.PUBLIC
751
+ }));
752
+ mockResultRepo.save.mockResolvedValue(buildFormResult({
753
+ isDraft: true
754
+ }));
755
+ await service.submitForm({
756
+ formId: 'form-uuid-1',
757
+ data: {},
758
+ isDraft: true
759
+ }, null, true);
760
+ expect(publish.mock.calls[0][0].name).toBe('form-builder.form_result.draft-saved');
761
+ });
762
+ it('does not publish when the module has events disabled', async ()=>{
763
+ EventBusRegistry.configureModule('form-builder', {
764
+ enabled: false
765
+ });
766
+ await buildService(false);
767
+ mockFormRepo.findOne.mockResolvedValue(buildForm({
768
+ accessType: FormAccessType.PUBLIC
769
+ }));
770
+ mockResultRepo.save.mockResolvedValue(buildFormResult());
771
+ await service.submitForm({
772
+ formId: 'form-uuid-1',
773
+ data: {}
774
+ }, null, true);
775
+ expect(publish).not.toHaveBeenCalled();
776
+ });
777
+ });
657
778
  });
@@ -1,6 +1,8 @@
1
1
  import { ModuleMetadata, Type } from '@nestjs/common';
2
2
  import { IBootstrapAppConfig, IDataSourceServiceOptions, IDynamicModuleConfig, IModuleOptionsFactory } from '@flusys/nestjs-core';
3
+ import { IModuleEventsConfig } from '@flusys/nestjs-shared/interfaces';
3
4
  export interface IFormBuilderConfig extends IDataSourceServiceOptions {
5
+ events?: IModuleEventsConfig;
4
6
  }
5
7
  export interface FormBuilderModuleOptions extends IDynamicModuleConfig {
6
8
  bootstrapAppConfig?: IBootstrapAppConfig;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flusys/nestjs-form-builder",
3
- "version": "6.4.0",
3
+ "version": "7.0.0-beta.1",
4
4
  "description": "Dynamic form builder module with schema versioning and access control",
5
5
  "main": "cjs/index.js",
6
6
  "module": "fesm/index.js",
@@ -84,7 +84,7 @@
84
84
  "express": "^5.0.0"
85
85
  },
86
86
  "dependencies": {
87
- "@flusys/nestjs-core": "6.4.0",
88
- "@flusys/nestjs-shared": "6.4.0"
87
+ "@flusys/nestjs-core": "7.0.0-beta.1",
88
+ "@flusys/nestjs-shared": "7.0.0-beta.1"
89
89
  }
90
90
  }
@@ -33,6 +33,8 @@ export declare class FormResultService extends ApiService<CreateFormResultDto, U
33
33
  submitForm(dto: SubmitFormDto, user: ILoggedUserInfo | null, isPublic?: boolean): Promise<IFormResult>;
34
34
  getMyDraft(formId: string, user: ILoggedUserInfo): Promise<IFormResult | null>;
35
35
  updateDraft(draftId: string, dto: SubmitFormDto, user: ILoggedUserInfo): Promise<IFormResult>;
36
+ private publishSubmissionEvent;
37
+ private invalidateResultCache;
36
38
  getByFormId(formId: string, user: ILoggedUserInfo | null, pagination?: {
37
39
  page?: number;
38
40
  pageSize?: number;