@solidstarters/solid-core 1.2.163 → 1.2.165

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 (139) hide show
  1. package/dist/controllers/test-queue.controller.d.ts +1 -1
  2. package/dist/controllers/test-queue.controller.d.ts.map +1 -1
  3. package/dist/controllers/test-queue.controller.js +6 -4
  4. package/dist/controllers/test-queue.controller.js.map +1 -1
  5. package/dist/jobs/chatter-queue-options.d.ts +8 -0
  6. package/dist/jobs/chatter-queue-options.d.ts.map +1 -0
  7. package/dist/jobs/chatter-queue-options.js +10 -0
  8. package/dist/jobs/chatter-queue-options.js.map +1 -0
  9. package/dist/jobs/chatter-queue-publisher.service.d.ts +22 -0
  10. package/dist/jobs/chatter-queue-publisher.service.d.ts.map +1 -0
  11. package/dist/jobs/chatter-queue-publisher.service.js +39 -0
  12. package/dist/jobs/chatter-queue-publisher.service.js.map +1 -0
  13. package/dist/jobs/chatter-queue-subscriber.service.d.ts +17 -0
  14. package/dist/jobs/chatter-queue-subscriber.service.d.ts.map +1 -0
  15. package/dist/jobs/chatter-queue-subscriber.service.js +59 -0
  16. package/dist/jobs/chatter-queue-subscriber.service.js.map +1 -0
  17. package/dist/jobs/{database/computed-field-evaluation-publisher.service.d.ts → computed-field-evaluation-publisher.service.d.ts} +2 -2
  18. package/dist/jobs/computed-field-evaluation-publisher.service.d.ts.map +1 -0
  19. package/dist/jobs/{database/computed-field-evaluation-publisher.service.js → computed-field-evaluation-publisher.service.js} +8 -8
  20. package/dist/jobs/computed-field-evaluation-publisher.service.js.map +1 -0
  21. package/dist/jobs/{database/computed-field-evaluation-queue-options.d.ts → computed-field-evaluation-queue-options.d.ts} +1 -1
  22. package/dist/jobs/computed-field-evaluation-queue-options.d.ts.map +1 -0
  23. package/dist/jobs/{database/computed-field-evaluation-queue-options.js → computed-field-evaluation-queue-options.js} +2 -2
  24. package/dist/jobs/computed-field-evaluation-queue-options.js.map +1 -0
  25. package/dist/jobs/{database/computed-field-evaluation-subscriber.service.d.ts → computed-field-evaluation-subscriber.service.d.ts} +3 -3
  26. package/dist/jobs/computed-field-evaluation-subscriber.service.d.ts.map +1 -0
  27. package/dist/jobs/computed-field-evaluation-subscriber.service.js +51 -0
  28. package/dist/jobs/computed-field-evaluation-subscriber.service.js.map +1 -0
  29. package/dist/jobs/database/computed-field-evaluation-publisher-database.service.d.ts +12 -0
  30. package/dist/jobs/database/computed-field-evaluation-publisher-database.service.d.ts.map +1 -0
  31. package/dist/jobs/database/computed-field-evaluation-publisher-database.service.js +39 -0
  32. package/dist/jobs/database/computed-field-evaluation-publisher-database.service.js.map +1 -0
  33. package/dist/jobs/database/computed-field-evaluation-queue-options-database.d.ts +8 -0
  34. package/dist/jobs/database/computed-field-evaluation-queue-options-database.d.ts.map +1 -0
  35. package/dist/jobs/database/computed-field-evaluation-queue-options-database.js +10 -0
  36. package/dist/jobs/database/computed-field-evaluation-queue-options-database.js.map +1 -0
  37. package/dist/jobs/database/computed-field-evaluation-subscriber-database.service.d.ts +18 -0
  38. package/dist/jobs/database/computed-field-evaluation-subscriber-database.service.d.ts.map +1 -0
  39. package/dist/jobs/database/{computed-field-evaluation-subscriber.service.js → computed-field-evaluation-subscriber-database.service.js} +8 -8
  40. package/dist/jobs/database/computed-field-evaluation-subscriber-database.service.js.map +1 -0
  41. package/dist/jobs/database/generate-code-queue-options-database.js +2 -2
  42. package/dist/jobs/database/generate-code-queue-options-database.js.map +1 -1
  43. package/dist/jobs/database/test-queue-subscriber-database.service.d.ts.map +1 -1
  44. package/dist/jobs/database/test-queue-subscriber-database.service.js +7 -1
  45. package/dist/jobs/database/test-queue-subscriber-database.service.js.map +1 -1
  46. package/dist/jobs/generate-code-publisher.service.d.ts +11 -0
  47. package/dist/jobs/generate-code-publisher.service.d.ts.map +1 -0
  48. package/dist/jobs/generate-code-publisher.service.js +39 -0
  49. package/dist/jobs/generate-code-publisher.service.js.map +1 -0
  50. package/dist/jobs/generate-code-queue-options.d.ts +8 -0
  51. package/dist/jobs/generate-code-queue-options.d.ts.map +1 -0
  52. package/dist/jobs/generate-code-queue-options.js +10 -0
  53. package/dist/jobs/generate-code-queue-options.js.map +1 -0
  54. package/dist/jobs/generate-code-subscriber.service.d.ts +18 -0
  55. package/dist/jobs/generate-code-subscriber.service.d.ts.map +1 -0
  56. package/dist/jobs/generate-code-subscriber.service.js +70 -0
  57. package/dist/jobs/generate-code-subscriber.service.js.map +1 -0
  58. package/dist/jobs/test-queue-subscriber.service.d.ts +1 -1
  59. package/dist/jobs/test-queue-subscriber.service.d.ts.map +1 -1
  60. package/dist/jobs/test-queue-subscriber.service.js +9 -6
  61. package/dist/jobs/test-queue-subscriber.service.js.map +1 -1
  62. package/dist/jobs/trigger-mcp-client-publisher.service.d.ts +11 -0
  63. package/dist/jobs/trigger-mcp-client-publisher.service.d.ts.map +1 -0
  64. package/dist/jobs/trigger-mcp-client-publisher.service.js +39 -0
  65. package/dist/jobs/trigger-mcp-client-publisher.service.js.map +1 -0
  66. package/dist/jobs/trigger-mcp-client-queue-options.d.ts +8 -0
  67. package/dist/jobs/trigger-mcp-client-queue-options.d.ts.map +1 -0
  68. package/dist/jobs/trigger-mcp-client-queue-options.js +10 -0
  69. package/dist/jobs/trigger-mcp-client-queue-options.js.map +1 -0
  70. package/dist/jobs/trigger-mcp-client-subscriber.service.d.ts +18 -0
  71. package/dist/jobs/trigger-mcp-client-subscriber.service.d.ts.map +1 -0
  72. package/dist/jobs/trigger-mcp-client-subscriber.service.js +103 -0
  73. package/dist/jobs/trigger-mcp-client-subscriber.service.js.map +1 -0
  74. package/dist/jobs/twilio-sms-publisher.service.d.ts +11 -0
  75. package/dist/jobs/twilio-sms-publisher.service.d.ts.map +1 -0
  76. package/dist/jobs/twilio-sms-publisher.service.js +39 -0
  77. package/dist/jobs/twilio-sms-publisher.service.js.map +1 -0
  78. package/dist/jobs/twilio-sms-queue-options.d.ts +8 -0
  79. package/dist/jobs/twilio-sms-queue-options.d.ts.map +1 -0
  80. package/dist/jobs/twilio-sms-queue-options.js +10 -0
  81. package/dist/jobs/twilio-sms-queue-options.js.map +1 -0
  82. package/dist/jobs/twilio-sms-subscriber.service.d.ts +17 -0
  83. package/dist/jobs/twilio-sms-subscriber.service.d.ts.map +1 -0
  84. package/dist/jobs/twilio-sms-subscriber.service.js +48 -0
  85. package/dist/jobs/twilio-sms-subscriber.service.js.map +1 -0
  86. package/dist/services/queues/database-publisher.service.js +2 -2
  87. package/dist/services/queues/database-publisher.service.js.map +1 -1
  88. package/dist/services/queues/database-subscriber.service.d.ts.map +1 -1
  89. package/dist/services/queues/database-subscriber.service.js +2 -1
  90. package/dist/services/queues/database-subscriber.service.js.map +1 -1
  91. package/dist/services/queues/publisher-factory.service.js +1 -1
  92. package/dist/services/queues/publisher-factory.service.js.map +1 -1
  93. package/dist/solid-core.module.d.ts.map +1 -1
  94. package/dist/solid-core.module.js +21 -4
  95. package/dist/solid-core.module.js.map +1 -1
  96. package/dist/subscribers/audit.subscriber.d.ts +8 -0
  97. package/dist/subscribers/audit.subscriber.d.ts.map +1 -1
  98. package/dist/subscribers/audit.subscriber.js +52 -3
  99. package/dist/subscribers/audit.subscriber.js.map +1 -1
  100. package/dist/subscribers/computed-entity-field.subscriber.d.ts +3 -3
  101. package/dist/subscribers/computed-entity-field.subscriber.d.ts.map +1 -1
  102. package/dist/subscribers/computed-entity-field.subscriber.js +5 -7
  103. package/dist/subscribers/computed-entity-field.subscriber.js.map +1 -1
  104. package/dist/tsconfig.tsbuildinfo +1 -1
  105. package/package.json +1 -1
  106. package/src/controllers/test-queue.controller.ts +4 -3
  107. package/src/jobs/chatter-queue-options.ts +9 -0
  108. package/src/jobs/chatter-queue-publisher.service.ts +37 -0
  109. package/src/jobs/chatter-queue-subscriber.service.ts +46 -0
  110. package/src/jobs/computed-field-evaluation-publisher.service.ts +23 -0
  111. package/src/jobs/{database/computed-field-evaluation-queue-options.ts → computed-field-evaluation-queue-options.ts} +2 -2
  112. package/src/jobs/computed-field-evaluation-subscriber.service.ts +38 -0
  113. package/src/jobs/database/{computed-field-evaluation-publisher.service.ts → computed-field-evaluation-publisher-database.service.ts} +2 -2
  114. package/src/jobs/database/computed-field-evaluation-queue-options-database.ts +9 -0
  115. package/src/jobs/database/{computed-field-evaluation-subscriber.service.ts → computed-field-evaluation-subscriber-database.service.ts} +2 -2
  116. package/src/jobs/database/generate-code-queue-options-database.ts +2 -2
  117. package/src/jobs/database/test-queue-subscriber-database.service.ts +10 -2
  118. package/src/jobs/generate-code-publisher.service.ts +23 -0
  119. package/src/jobs/generate-code-queue-options.ts +9 -0
  120. package/src/jobs/generate-code-subscriber.service.ts +59 -0
  121. package/src/jobs/test-queue-subscriber.service.ts +15 -7
  122. package/src/jobs/trigger-mcp-client-publisher.service.ts +22 -0
  123. package/src/jobs/trigger-mcp-client-queue-options.ts +9 -0
  124. package/src/jobs/trigger-mcp-client-subscriber.service.ts +104 -0
  125. package/src/jobs/twilio-sms-publisher.service.ts +23 -0
  126. package/src/jobs/twilio-sms-queue-options.ts +9 -0
  127. package/src/jobs/twilio-sms-subscriber.service.ts +32 -0
  128. package/src/services/queues/database-publisher.service.ts +2 -2
  129. package/src/services/queues/database-subscriber.service.ts +2 -1
  130. package/src/services/queues/publisher-factory.service.ts +1 -1
  131. package/src/solid-core.module.ts +33 -8
  132. package/src/subscribers/audit.subscriber.ts +235 -5
  133. package/src/subscribers/computed-entity-field.subscriber.ts +7 -5
  134. package/dist/jobs/database/computed-field-evaluation-publisher.service.d.ts.map +0 -1
  135. package/dist/jobs/database/computed-field-evaluation-publisher.service.js.map +0 -1
  136. package/dist/jobs/database/computed-field-evaluation-queue-options.d.ts.map +0 -1
  137. package/dist/jobs/database/computed-field-evaluation-queue-options.js.map +0 -1
  138. package/dist/jobs/database/computed-field-evaluation-subscriber.service.d.ts.map +0 -1
  139. package/dist/jobs/database/computed-field-evaluation-subscriber.service.js.map +0 -1
@@ -94,6 +94,10 @@ import { SmsQueuePublisher } from './jobs/sms-publisher.service';
94
94
  import { SmsQueueSubscriber } from './jobs/sms-subscriber.service';
95
95
  import { TestQueuePublisher } from './jobs/test-queue-publisher.service';
96
96
  import { TestQueueSubscriber } from './jobs/test-queue-subscriber.service';
97
+
98
+ // import { ChatterQueuePublisher } from './jobs/chatter-queue-publisher.service';
99
+ // import { ChatterQueueSubscriber } from './jobs/chatter-queue-subscriber.service';
100
+
97
101
  import { Msg91WhatsappQueuePublisher } from './jobs/msg91-whatsapp-publisher.service';
98
102
  import { Msg91WhatsappQueueSubscriber } from './jobs/msg91-whatsapp-subscriber.service';
99
103
  import { UserRegistrationListener } from './listeners/user-registration.listener';
@@ -176,8 +180,8 @@ import { ModelMetadataHelperService } from './helpers/model-metadata-helper.serv
176
180
  import { ModuleMetadataHelperService } from './helpers/module-metadata-helper.service';
177
181
  import { ApiEmailQueuePublisherDatabase } from './jobs/database/api-email-publisher-database.service';
178
182
  import { ApiEmailQueueSubscriberDatabase } from './jobs/database/api-email-subscriber-database.service';
179
- import { ComputedFieldEvaluationPublisher } from './jobs/database/computed-field-evaluation-publisher.service';
180
- import { ComputedFieldEvaluationSubscriber } from './jobs/database/computed-field-evaluation-subscriber.service';
183
+ import { ComputedFieldEvaluationPublisherDatabase } from './jobs/database/computed-field-evaluation-publisher-database.service';
184
+ import { ComputedFieldEvaluationSubscriberDatabase } from './jobs/database/computed-field-evaluation-subscriber-database.service';
181
185
  import { SmtpEmailQueuePublisherDatabase } from './jobs/database/smtp-email-publisher-database.service';
182
186
  import { SmtpEmailQueueSubscriberDatabase } from './jobs/database/smtp-email-subscriber-database.service';
183
187
  import { GenerateCodePublisherDatabase } from './jobs/database/generate-code-publisher-database.service';
@@ -288,6 +292,14 @@ import { ErrorMapperService } from './helpers/error-mapper.service';
288
292
  import { IngestCommand } from './commands/ingest.command';
289
293
  import { R2RHelperService } from './services/genai/r2r-helper.service';
290
294
  import { IngestMetadataService } from './services/genai/ingest-metadata.service';
295
+ import { ComputedFieldEvaluationPublisherRabbitmq } from './jobs/computed-field-evaluation-publisher.service';
296
+ import { ComputedFieldEvaluationSubscriberRabbitmq } from './jobs/computed-field-evaluation-subscriber.service';
297
+ import { GenerateCodePublisherRabbitmq } from './jobs/generate-code-publisher.service';
298
+ import { GenerateCodeSubscriberRabbitmq } from './jobs/generate-code-subscriber.service';
299
+ import { TriggerMcpClientPublisherRabbitmq } from './jobs/trigger-mcp-client-publisher.service';
300
+ import { TriggerMcpClientSubscriberRabbitmq } from './jobs/trigger-mcp-client-subscriber.service';
301
+ import { TwilioSmsQueuePublisherRabbitmq } from './jobs/twilio-sms-publisher.service';
302
+ import { TwilioSmsQueueSubscriberRabbitmq } from './jobs/twilio-sms-subscriber.service';
291
303
 
292
304
 
293
305
  @Global()
@@ -368,10 +380,10 @@ import { IngestMetadataService } from './services/genai/ingest-metadata.service'
368
380
  inject: [ConfigService],
369
381
  useFactory: (configService: ConfigService) => ({
370
382
  throttlers: [
371
- { name: 'short', ttl: seconds(10), limit: 10 },
372
- { name: 'login', ttl: seconds(10), limit: 5 },
373
- { name: 'burst', ttl: seconds(1), limit: 100 },
374
- { name: 'sustained', ttl: seconds(300), limit: 500 },
383
+ { name: 'short', ttl: seconds(10), limit: 10 },
384
+ { name: 'login', ttl: seconds(10), limit: 5 },
385
+ { name: 'burst', ttl: seconds(1), limit: 100 },
386
+ { name: 'sustained', ttl: seconds(300), limit: 500 },
375
387
  ],
376
388
  storage: isRedisConfigured(configService) ? new ThrottlerStorageRedisService(`redis://${configService.get<string>('REDIS_HOST')}:${configService.get<string>('REDIS_PORT')}`) : undefined,
377
389
  }),
@@ -494,6 +506,8 @@ import { IngestMetadataService } from './services/genai/ingest-metadata.service'
494
506
 
495
507
  TriggerMcpClientPublisherDatabase,
496
508
  TriggerMcpClientSubscriberDatabase,
509
+ TriggerMcpClientPublisherRabbitmq,
510
+ TriggerMcpClientSubscriberRabbitmq,
497
511
 
498
512
  SmtpEmailQueuePublisherRabbitmq,
499
513
  SmtpEmailQueueSubscriberRabbitmq,
@@ -509,6 +523,8 @@ import { IngestMetadataService } from './services/genai/ingest-metadata.service'
509
523
  SmsQueueSubscriberDatabase,
510
524
  TwilioSmsQueuePublisherDatabase,
511
525
  TwilioSmsQueueSubscriberDatabase,
526
+ TwilioSmsQueuePublisherRabbitmq,
527
+ TwilioSmsQueueSubscriberRabbitmq,
512
528
  OTPQueuePublisher,
513
529
  OTPQueueSubscriber,
514
530
  OTPQueuePublisherDatabase,
@@ -543,10 +559,17 @@ import { IngestMetadataService } from './services/genai/ingest-metadata.service'
543
559
  UserRegistrationListener,
544
560
  TestQueuePublisher,
545
561
  TestQueueSubscriber,
562
+
563
+ // ChatterQueuePublisher,
564
+ // ChatterQueueSubscriber,
565
+
546
566
  TestQueuePublisherDatabase,
547
567
  TestQueueSubscriberDatabase,
548
568
  GenerateCodePublisherDatabase,
549
569
  GenerateCodeSubscriberDatabase,
570
+ GenerateCodePublisherRabbitmq,
571
+ GenerateCodeSubscriberRabbitmq,
572
+ OTPQueuePublisher,
550
573
  MqMessageQueueService,
551
574
  MqMessageService,
552
575
  ScheduledJobService,
@@ -584,8 +607,10 @@ import { IngestMetadataService } from './services/genai/ingest-metadata.service'
584
607
  SystemFieldsSeederService,
585
608
  FieldMetadataRepository,
586
609
  ComputedEntityFieldSubscriber,
587
- ComputedFieldEvaluationPublisher,
588
- ComputedFieldEvaluationSubscriber,
610
+ ComputedFieldEvaluationPublisherDatabase,
611
+ ComputedFieldEvaluationSubscriberDatabase,
612
+ ComputedFieldEvaluationPublisherRabbitmq,
613
+ ComputedFieldEvaluationSubscriberRabbitmq,
589
614
  ConcatEntityComputedFieldProvider,
590
615
  UserActivityHistoryService,
591
616
  DashboardService,
@@ -6,6 +6,12 @@ import { ChatterMessageService } from '../services/chatter-message.service';
6
6
  import { lowerFirst } from 'src/helpers/string.helper';
7
7
  import { ModelMetadataHelperService } from 'src/helpers/model-metadata-helper.service';
8
8
 
9
+
10
+ type DeferredCall =
11
+ | { kind: 'insert'; args: Parameters<ChatterMessageService['postAuditMessageOnInsert']> }
12
+ | { kind: 'update'; args: Parameters<ChatterMessageService['postAuditMessageOnUpdate']> }
13
+ | { kind: 'delete'; args: Parameters<ChatterMessageService['postAuditMessageOnDelete']> };
14
+
9
15
  @Injectable()
10
16
  @EventSubscriber()
11
17
  export class AuditSubscriber implements EntitySubscriberInterface {
@@ -16,11 +22,21 @@ export class AuditSubscriber implements EntitySubscriberInterface {
16
22
  private readonly chatterMessageService: ChatterMessageService,
17
23
  @InjectRepository(ModelMetadata)
18
24
  private readonly modelMetadataRepo: Repository<ModelMetadata>,
19
- private readonly modelMetadataHelperService : ModelMetadataHelperService,
25
+ private readonly modelMetadataHelperService: ModelMetadataHelperService,
20
26
  ) {
21
27
  this.dataSource.subscribers.push(this);
22
28
  }
23
29
 
30
+ // Per-transaction buffer (auto-GC when queryRunner is gone)
31
+ private perTxn = new WeakMap<any, DeferredCall[]>();
32
+
33
+ private enqueue(event: { queryRunner: any }, call: DeferredCall) {
34
+ const qr = event.queryRunner;
35
+ const arr = this.perTxn.get(qr) ?? [];
36
+ arr.push(call);
37
+ this.perTxn.set(qr, arr);
38
+ }
39
+
24
40
  private async shouldTrackAudit(entity: any, metadata: EntityMetadata): Promise<boolean> {
25
41
  const model = await this.modelMetadataRepo.findOne({
26
42
  where: {
@@ -56,19 +72,233 @@ export class AuditSubscriber implements EntitySubscriberInterface {
56
72
 
57
73
  async afterInsert(event: InsertEvent<any>) {
58
74
  if (await this.shouldTrackAudit(event.entity, event.metadata)) {
59
- await this.chatterMessageService.postAuditMessageOnInsert(event.entity, event.metadata);
75
+ // await this.chatterMessageService.postAuditMessageOnInsert(event.entity, event.metadata);
76
+ this.enqueue(event, {
77
+ kind: 'insert',
78
+ args: [event.entity, event.metadata] as Parameters<ChatterMessageService['postAuditMessageOnInsert']>,
79
+ });
60
80
  }
61
81
  }
62
82
 
63
83
  async afterUpdate(event: UpdateEvent<any>) {
64
84
  if (await this.shouldTrackAudit(event.entity, event.metadata)) {
65
- await this.chatterMessageService.postAuditMessageOnUpdate(event.entity, event.metadata, event.databaseEntity, event.updatedColumns || []);
85
+ // await this.chatterMessageService.postAuditMessageOnUpdate(event.entity, event.metadata, event.databaseEntity, event.updatedColumns || []);
86
+ this.enqueue(event, {
87
+ kind: 'update',
88
+ args: [
89
+ event.entity, // entity (after)
90
+ event.metadata,
91
+ event.databaseEntity, // entity (before)
92
+ event.updatedColumns ?? [],
93
+ ] as Parameters<ChatterMessageService['postAuditMessageOnUpdate']>,
94
+ });
66
95
  }
67
96
  }
68
97
 
69
98
  async afterRemove(event: RemoveEvent<any>) {
70
99
  if (await this.shouldTrackAudit(event.entity, event.metadata)) {
71
- await this.chatterMessageService.postAuditMessageOnDelete(event.entity, event.metadata, event.databaseEntity);
100
+ // await this.chatterMessageService.postAuditMessageOnDelete(event.entity, event.metadata, event.databaseEntity);
101
+ this.enqueue(event, {
102
+ kind: 'delete',
103
+ args: [
104
+ event.entity,
105
+ event.metadata,
106
+ event.databaseEntity,
107
+ ] as Parameters<ChatterMessageService['postAuditMessageOnDelete']>,
108
+ });
109
+ }
110
+ }
111
+
112
+ // --------- transaction lifecycle ----------
113
+ async afterTransactionCommit(event: { queryRunner: any }) {
114
+ const batch = this.perTxn.get(event.queryRunner) ?? [];
115
+ this.perTxn.delete(event.queryRunner);
116
+
117
+ // Now we’re OUTSIDE the DB transaction — safe to do I/O/DB writes inside chatter service.
118
+ for (const item of batch) {
119
+ try {
120
+ switch (item.kind) {
121
+ case 'insert': await this.chatterMessageService.postAuditMessageOnInsert(...item.args); break;
122
+ case 'update': await this.chatterMessageService.postAuditMessageOnUpdate(...item.args); break;
123
+ case 'delete': await this.chatterMessageService.postAuditMessageOnDelete(...item.args); break;
124
+ }
125
+ } catch (e) {
126
+ // Best effort: log and continue; your core txn was already committed
127
+ // Optionally: send to a generic error logger/metric here
128
+ }
72
129
  }
73
130
  }
74
- }
131
+
132
+ afterTransactionRollback(event: { queryRunner: any }) {
133
+ // Drop buffered calls; the write never happened
134
+ this.perTxn.delete(event.queryRunner);
135
+ }
136
+ }
137
+
138
+ // import { DataSource, EntityMetadata, EntitySubscriberInterface, EventSubscriber, InsertEvent, RemoveEvent, UpdateEvent } from 'typeorm';
139
+ // import { Injectable } from '@nestjs/common';
140
+ // import { InjectDataSource, InjectRepository } from '@nestjs/typeorm';
141
+ // import { Repository } from 'typeorm';
142
+ // import { ModelMetadata } from '../entities/model-metadata.entity';
143
+ // import { lowerFirst } from 'src/helpers/string.helper';
144
+ // import { ModelMetadataHelperService } from 'src/helpers/model-metadata-helper.service';
145
+ // import { ChatterMessagePayload } from 'src/jobs/chatter-queue-publisher.service';
146
+ // import { RequestContextService } from 'src/services/request-context.service';
147
+ // import { PublisherFactory } from 'src/services/queues/publisher-factory.service';
148
+
149
+ // @EventSubscriber()
150
+ // @Injectable()
151
+ // export class AuditSubscriber implements EntitySubscriberInterface {
152
+ // private perTxn = new WeakMap<any, ChatterMessagePayload[]>();
153
+
154
+ // constructor(
155
+ // @InjectDataSource() private readonly dataSource: DataSource,
156
+ // @InjectRepository(ModelMetadata) private readonly modelMetadataRepo: Repository<ModelMetadata>,
157
+ // private readonly modelMetadataHelperService: ModelMetadataHelperService,
158
+ // private readonly requestContext: RequestContextService,
159
+ // private readonly publisherFactory: PublisherFactory<any>
160
+ // ) {
161
+ // this.dataSource.subscribers.push(this);
162
+ // }
163
+
164
+ // // --- small cache to avoid metadata queries on every row ---
165
+ // private modelCache = new Map<string, { enable: boolean; fields: Array<{ name: string; enableAuditTracking: boolean; type: string; relationType?: string }>; ts: number }>();
166
+ // private cacheTTLms = 60_000;
167
+
168
+ // private async shouldTrackAudit(entity: any, metadata: EntityMetadata): Promise<{ enable: boolean; auditFields?: string[] }> {
169
+ // const key = metadata.name;
170
+ // const now = Date.now();
171
+ // const cached = this.modelCache.get(key);
172
+ // if (cached && (now - cached.ts) < this.cacheTTLms) {
173
+ // if (!cached.enable) return { enable: false };
174
+ // const fields = cached.fields.filter(f =>
175
+ // f.enableAuditTracking &&
176
+ // !['mediaSingle', 'mediaMultiple', 'computed', 'richText', 'json'].includes(f.type) &&
177
+ // !(f.type === 'relation' && f.relationType === 'one-to-many')
178
+ // );
179
+ // const present = fields.map(f => f.name).filter(n => entity?.[n] !== undefined);
180
+ // return { enable: present.length > 0, auditFields: present };
181
+ // }
182
+
183
+ // const model = await this.modelMetadataRepo.findOne({
184
+ // where: { singularName: lowerFirst(metadata.name) },
185
+ // relations: { fields: true, module: true },
186
+ // });
187
+ // const enable = !!model?.enableAuditTracking;
188
+ // const fields = model?.fields ?? [];
189
+ // this.modelCache.set(key, { enable, fields, ts: now });
190
+
191
+ // if (!enable) return { enable: false };
192
+ // const filtered = fields.filter(f =>
193
+ // f.enableAuditTracking &&
194
+ // !['mediaSingle', 'mediaMultiple', 'computed', 'richText', 'json'].includes(f.type) &&
195
+ // !(f.type === 'relation' && f.relationType === 'one-to-many')
196
+ // );
197
+ // const present = filtered.map(f => f.name).filter(n => entity?.[n] !== undefined);
198
+ // return { enable: present.length > 0, auditFields: present };
199
+ // }
200
+
201
+ // private push(event: { queryRunner: any }, msg: ChatterMessagePayload) {
202
+ // const arr = this.perTxn.get(event.queryRunner) ?? [];
203
+ // arr.push(msg);
204
+ // this.perTxn.set(event.queryRunner, arr);
205
+ // }
206
+
207
+ // async afterInsert(event: InsertEvent<any>) {
208
+ // if (!event.entity) return;
209
+ // const enable = await this.shouldTrackAudit(event.entity, event.metadata);
210
+ // if (!enable) return;
211
+
212
+ // const payload: ChatterMessagePayload = {
213
+ // eventType: 'insert',
214
+ // model: event.metadata.name,
215
+ // entityId: String(event.entity.id ?? event.entity.uuid ?? ''),
216
+ // occurredAt: new Date().toISOString(),
217
+ // after: this.safeCopy(event.entity),
218
+ // userId: this.getUserId(),
219
+ // };
220
+ // this.push(event, payload);
221
+ // }
222
+
223
+ // async afterUpdate(event: UpdateEvent<any>) {
224
+ // // Updated entity may be null if you used raw query; fall back to databaseEntity
225
+ // const current = event.entity ?? {};
226
+ // const before = event.databaseEntity ?? {};
227
+ // const { enable, auditFields } = await this.shouldTrackAudit(current, event.metadata);
228
+ // if (!enable) return;
229
+
230
+ // const changedCols = (event.updatedColumns || []).map(c => c.propertyName);
231
+ // const payload: ChatterMessagePayload = {
232
+ // eventType: 'update',
233
+ // model: event.metadata.name,
234
+ // entityId: String((current as any).id ?? (before as any).id ?? ''),
235
+ // occurredAt: new Date().toISOString(),
236
+ // before: this.pick(before, auditFields || changedCols),
237
+ // after: this.pick(current, auditFields || changedCols),
238
+ // diff: changedCols,
239
+ // userId: this.getUserId(),
240
+ // };
241
+ // this.push(event, payload);
242
+ // }
243
+
244
+ // async afterRemove(event: RemoveEvent<any>) {
245
+ // const base = event.entity ?? event.databaseEntity;
246
+ // if (!base) return;
247
+
248
+ // const { enable } = await this.shouldTrackAudit(base, event.metadata);
249
+ // if (!enable) return;
250
+
251
+ // const payload: ChatterMessagePayload = {
252
+ // eventType: 'delete',
253
+ // model: event.metadata.name,
254
+ // entityId: String((base as any).id ?? ''),
255
+ // occurredAt: new Date().toISOString(),
256
+ // before: this.safeCopy(base),
257
+ // userId: this.getUserId(),
258
+ // };
259
+ // this.push(event, payload);
260
+ // }
261
+
262
+ // // Publish AFTER the transaction commits -> no idle-in-transaction
263
+ // async afterTransactionCommit(event: { queryRunner: any }) {
264
+ // const batch = this.perTxn.get(event.queryRunner) ?? [];
265
+ // this.perTxn.delete(event.queryRunner);
266
+ // for (const msg of batch) {
267
+ // try {
268
+ // await this.publisherFactory.publish({ payload: msg, parentEntity: msg.model, parentEntityId: msg.entityId }, 'ChatterQueuePublisher');
269
+ // } catch (err) {
270
+ // // log + optionally send to a DLQ or retry queue
271
+ // // do NOT throw; commit already happened
272
+ // // your RabbitMqPublisher likely tracks failures in MqMessage tables anyway
273
+ // }
274
+ // }
275
+ // }
276
+
277
+ // afterTransactionRollback(event: { queryRunner: any }) {
278
+ // this.perTxn.delete(event.queryRunner);
279
+ // }
280
+
281
+ // // --- small helpers to keep payloads JSON-safe and small ---
282
+ // private safeCopy(obj: any) {
283
+ // try {
284
+ // return JSON.parse(JSON.stringify(obj));
285
+ // } catch {
286
+ // return {}; // strip circular refs
287
+ // }
288
+ // }
289
+
290
+ // private pick(obj: any, keys: string[]) {
291
+ // const out: any = {};
292
+ // for (const k of keys) out[k] = obj?.[k];
293
+ // return this.safeCopy(out);
294
+ // }
295
+
296
+ // private getUserId(): string | null {
297
+
298
+ // const activeUser = this.requestContext.getActiveUser();
299
+ // if (activeUser?.sub)
300
+ // return String(activeUser.sub);
301
+ // }
302
+
303
+
304
+ // }
@@ -4,7 +4,7 @@ import { InjectDataSource } from "@nestjs/typeorm";
4
4
  import { ComputedFieldTriggerOperation } from "src/dtos/create-field-metadata.dto";
5
5
  import { ComputedFieldMetadata, SolidRegistry } from "src/helpers/solid-registry";
6
6
  import { IEntityPreComputeFieldProvider } from "src/interfaces";
7
- import { ComputedFieldEvaluationPublisher } from "src/jobs/database/computed-field-evaluation-publisher.service";
7
+ import { PublisherFactory } from "src/services/queues/publisher-factory.service";
8
8
  import { DataSource, EntitySubscriberInterface, EventSubscriber, InsertEvent, UpdateEvent } from "typeorm";
9
9
 
10
10
  // Create an interface i.e ComputedFieldEvaluationPayload which has same fields as the ComputedFieldMetadata and an additional field for the database entity
@@ -20,7 +20,8 @@ export class ComputedEntityFieldSubscriber implements EntitySubscriberInterface
20
20
  @InjectDataSource()
21
21
  private readonly dataSource: DataSource,
22
22
  private readonly solidRegistry: SolidRegistry,
23
- private readonly computedFieldPublisher: ComputedFieldEvaluationPublisher,
23
+ private readonly publisherFactory: PublisherFactory<ComputedFieldEvaluationPayload>
24
+ // private readonly computedFieldPublisher: ComputedFieldEvaluationPublisherDatabase,
24
25
  ) {
25
26
  this.dataSource.subscribers.push(this);
26
27
  }
@@ -112,9 +113,10 @@ export class ComputedEntityFieldSubscriber implements EntitySubscriberInterface
112
113
  ...computedField,
113
114
  databaseEntity,
114
115
  };
115
- this.computedFieldPublisher.publish({
116
- payload
117
- });
116
+ this.publisherFactory.publish({payload}, 'ComputedFieldEvaluationPublisher')
117
+ // this.computedFieldPublisher.publish({
118
+ // payload
119
+ // });
118
120
  }
119
121
 
120
122
  }
@@ -1 +0,0 @@
1
- {"version":3,"file":"computed-field-evaluation-publisher.service.d.ts","sourceRoot":"","sources":["../../../src/jobs/database/computed-field-evaluation-publisher.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AAC9E,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gDAAgD,CAAC;AACnF,OAAO,EAAE,8BAA8B,EAAE,MAAM,kDAAkD,CAAC;AAGlG,qBACa,gCAAiC,SAAQ,iBAAiB,CAAC,8BAA8B,CAAC;IAE/F,SAAS,CAAC,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB;IACrD,SAAS,CAAC,QAAQ,CAAC,qBAAqB,EAAE,qBAAqB;gBAD5C,gBAAgB,EAAE,gBAAgB,EAClC,qBAAqB,EAAE,qBAAqB;IAKnE,OAAO,IAAI,mBAAmB;CAKjC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"computed-field-evaluation-publisher.service.js","sourceRoot":"","sources":["../../../src/jobs/database/computed-field-evaluation-publisher.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAA4C;AAE5C,sFAA8E;AAC9E,0EAAmE;AACnE,iGAAmF;AAEnF,wHAA4F;AAGrF,IAAM,gCAAgC,GAAtC,MAAM,gCAAiC,SAAQ,8CAAiD;IACnG,YACuB,gBAAkC,EAClC,qBAA4C;QAE/D,KAAK,CAAC,gBAAgB,EAAE,qBAAqB,CAAC,CAAC;QAH5B,qBAAgB,GAAhB,gBAAgB,CAAkB;QAClC,0BAAqB,GAArB,qBAAqB,CAAuB;IAGnE,CAAC;IAED,OAAO;QACH,OAAO;YACH,GAAG,iDAAmC;SACzC,CAAC;IACN,CAAC;CACJ,CAAA;AAbY,4EAAgC;2CAAhC,gCAAgC;IAD5C,IAAA,mBAAU,GAAE;qCAGgC,qCAAgB;QACX,gDAAqB;GAH1D,gCAAgC,CAa5C","sourcesContent":["import { Injectable } from \"@nestjs/common\";\nimport { QueuesModuleOptions } from \"src/interfaces\";\nimport { MqMessageQueueService } from \"src/services/mq-message-queue.service\";\nimport { MqMessageService } from \"src/services/mq-message.service\";\nimport { DatabasePublisher } from \"src/services/queues/database-publisher.service\";\nimport { ComputedFieldEvaluationPayload } from \"src/subscribers/computed-entity-field.subscriber\";\nimport computedFieldEvaluationQueueOptions from \"./computed-field-evaluation-queue-options\";\n\n@Injectable()\nexport class ComputedFieldEvaluationPublisher extends DatabasePublisher<ComputedFieldEvaluationPayload> {\n constructor(\n protected readonly mqMessageService: MqMessageService,\n protected readonly mqMessageQueueService: MqMessageQueueService,\n ) {\n super(mqMessageService, mqMessageQueueService);\n }\n\n options(): QueuesModuleOptions {\n return {\n ...computedFieldEvaluationQueueOptions\n };\n }\n}"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"computed-field-evaluation-queue-options.d.ts","sourceRoot":"","sources":["../../../src/jobs/database/computed-field-evaluation-queue-options.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;;;;;;AAI9C,wBAIE"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"computed-field-evaluation-queue-options.js","sourceRoot":"","sources":["../../../src/jobs/database/computed-field-evaluation-queue-options.ts"],"names":[],"mappings":";;AAAA,iDAA8C;AAE9C,MAAM,UAAU,GAAG,iCAAiC,CAAC;AAErD,kBAAe;IACX,IAAI,EAAE,8BAA8B;IACpC,IAAI,EAAE,uBAAU,CAAC,QAAQ;IACzB,SAAS,EAAE,UAAU;CACxB,CAAC","sourcesContent":["import { BrokerType } from \"../../interfaces\";\n\nconst QUEUE_NAME = 'computed_field_evaluation_queue';\n\nexport default {\n name: 'computedFieldEvaluationQueue',\n type: BrokerType.Database,\n queueName: QUEUE_NAME,\n};\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"computed-field-evaluation-subscriber.service.d.ts","sourceRoot":"","sources":["../../../src/jobs/database/computed-field-evaluation-subscriber.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EAAiE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACpH,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AAC9E,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,iDAAiD,CAAC;AACrF,OAAO,EAAE,8BAA8B,EAAE,MAAM,kDAAkD,CAAC;AAElG,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAE5D,qBACa,iCAAkC,SAAQ,kBAAkB,CAAC,8BAA8B,CAAC;IAEjG,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB;IAC3C,QAAQ,CAAC,qBAAqB,EAAE,qBAAqB;IACrD,QAAQ,CAAC,aAAa,EAAE,aAAa;IACrC,QAAQ,CAAC,MAAM,EAAE,aAAa;gBAHrB,gBAAgB,EAAE,gBAAgB,EAClC,qBAAqB,EAAE,qBAAqB,EAC5C,aAAa,EAAE,aAAa,EAC5B,MAAM,EAAE,aAAa;IAKlC,OAAO,IAAI,mBAAmB;IAQxB,SAAS,CAAC,OAAO,EAAE,YAAY,CAAC,8BAA8B,CAAC;CAOxE"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"computed-field-evaluation-subscriber.service.js","sourceRoot":"","sources":["../../../src/jobs/database/computed-field-evaluation-subscriber.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAA4C;AAC5C,iEAA2D;AAG3D,sFAA8E;AAC9E,0EAAmE;AACnE,mGAAqF;AAErF,wHAA4F;AAC5F,kEAA4D;AAGrD,IAAM,iCAAiC,GAAvC,MAAM,iCAAkC,SAAQ,gDAAkD;IACrG,YACa,gBAAkC,EAClC,qBAA4C,EAC5C,aAA4B,EAC5B,MAAqB;QAE9B,KAAK,CAAC,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,CAAC,CAAC;QAL9C,qBAAgB,GAAhB,gBAAgB,CAAkB;QAClC,0BAAqB,GAArB,qBAAqB,CAAuB;QAC5C,kBAAa,GAAb,aAAa,CAAe;QAC5B,WAAM,GAAN,MAAM,CAAe;IAGlC,CAAC;IAED,OAAO;QACH,OAAO;YACH,GAAG,iDAAmC;SACzC,CAAA;IACL,CAAC;IAID,KAAK,CAAC,SAAS,CAAC,OAAqD;QACjE,MAAM,EAAE,cAAc,EAAE,GAAG,qBAAqB,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC;QACrE,MAAM,QAAQ,GAAG,IAAI,CAAC,aAAa,CAAC,wBAAwB,CAAC,qBAAqB,CAAC,8BAA8B,CAAC,CAAC;QAEnH,MAAM,gBAAgB,GAAG,QAAQ,CAAC,QAAqD,CAAC;QACxF,MAAM,gBAAgB,CAAC,uBAAuB,CAAC,cAAc,EAAE,qBAAqB,CAAC,CAAC;IAC1F,CAAC;CACJ,CAAA;AAzBY,8EAAiC;4CAAjC,iCAAiC;IAD7C,IAAA,mBAAU,GAAE;qCAGsB,qCAAgB;QACX,gDAAqB;QAC7B,8BAAa;QACpB,8BAAa;GALzB,iCAAiC,CAyB7C","sourcesContent":["import { Injectable } from \"@nestjs/common\";\nimport { SolidRegistry } from \"src/helpers/solid-registry\";\nimport { IEntityPostComputeFieldProvider, IEntityComputedFieldProvider, QueuesModuleOptions } from \"src/interfaces\";\nimport { QueueMessage } from \"src/interfaces/mq\";\nimport { MqMessageQueueService } from \"src/services/mq-message-queue.service\";\nimport { MqMessageService } from \"src/services/mq-message.service\";\nimport { DatabaseSubscriber } from \"src/services/queues/database-subscriber.service\";\nimport { ComputedFieldEvaluationPayload } from \"src/subscribers/computed-entity-field.subscriber\";\nimport computedFieldEvaluationQueueOptions from \"./computed-field-evaluation-queue-options\";\nimport { PollerService } from \"src/services/poller.service\";\n\n@Injectable()\nexport class ComputedFieldEvaluationSubscriber extends DatabaseSubscriber<ComputedFieldEvaluationPayload> {\n constructor(\n readonly mqMessageService: MqMessageService,\n readonly mqMessageQueueService: MqMessageQueueService,\n readonly solidRegistry: SolidRegistry,\n readonly poller: PollerService,\n ) {\n super(mqMessageService, mqMessageQueueService, poller);\n }\n\n options(): QueuesModuleOptions {\n return {\n ...computedFieldEvaluationQueueOptions\n }\n }\n\n // This method will use the ComputedFieldEvaluationPayload to evaluate the computed fields\n // It will then call the corresponding provider computeAndSave method to perform the evaluation\n async subscribe(message: QueueMessage<ComputedFieldEvaluationPayload>) {\n const { databaseEntity, ...computedFieldMetadata } = message.payload;\n const provider = this.solidRegistry.getComputedFieldProvider(computedFieldMetadata.computedFieldValueProviderName);\n // Get the instance of the provider and assert it is of type IEntityComputedFieldProvider\n const providerInstance = provider.instance as IEntityPostComputeFieldProvider<any, any>; // IEntityComputedFieldProvider\n await providerInstance.postComputeAndSaveValue(databaseEntity, computedFieldMetadata); //FIXME There should some way to check/assert if the provider actually has a postComputeAndSaveValue\n }\n}"]}