@solidstarters/solid-core 1.2.146 → 1.2.148

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 (122) hide show
  1. package/dist/config/common.config.d.ts +10 -0
  2. package/dist/config/common.config.d.ts.map +1 -1
  3. package/dist/config/common.config.js +5 -0
  4. package/dist/config/common.config.js.map +1 -1
  5. package/dist/index.d.ts +2 -0
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +2 -0
  8. package/dist/index.js.map +1 -1
  9. package/dist/interfaces.d.ts +5 -5
  10. package/dist/interfaces.d.ts.map +1 -1
  11. package/dist/interfaces.js.map +1 -1
  12. package/dist/jobs/database/api-email-subscriber-database.service.d.ts +3 -1
  13. package/dist/jobs/database/api-email-subscriber-database.service.d.ts.map +1 -1
  14. package/dist/jobs/database/api-email-subscriber-database.service.js +6 -3
  15. package/dist/jobs/database/api-email-subscriber-database.service.js.map +1 -1
  16. package/dist/jobs/database/computed-field-evaluation-subscriber.service.d.ts +3 -1
  17. package/dist/jobs/database/computed-field-evaluation-subscriber.service.d.ts.map +1 -1
  18. package/dist/jobs/database/computed-field-evaluation-subscriber.service.js +6 -3
  19. package/dist/jobs/database/computed-field-evaluation-subscriber.service.js.map +1 -1
  20. package/dist/jobs/database/generate-code-subscriber-database.service.d.ts +3 -1
  21. package/dist/jobs/database/generate-code-subscriber-database.service.d.ts.map +1 -1
  22. package/dist/jobs/database/generate-code-subscriber-database.service.js +6 -3
  23. package/dist/jobs/database/generate-code-subscriber-database.service.js.map +1 -1
  24. package/dist/jobs/database/otp-subscriber-database.service.d.ts +3 -1
  25. package/dist/jobs/database/otp-subscriber-database.service.d.ts.map +1 -1
  26. package/dist/jobs/database/otp-subscriber-database.service.js +5 -2
  27. package/dist/jobs/database/otp-subscriber-database.service.js.map +1 -1
  28. package/dist/jobs/database/sms-subscriber-database.service.d.ts +4 -2
  29. package/dist/jobs/database/sms-subscriber-database.service.d.ts.map +1 -1
  30. package/dist/jobs/database/sms-subscriber-database.service.js +7 -4
  31. package/dist/jobs/database/sms-subscriber-database.service.js.map +1 -1
  32. package/dist/jobs/database/smtp-email-subscriber-database.service.d.ts +4 -2
  33. package/dist/jobs/database/smtp-email-subscriber-database.service.d.ts.map +1 -1
  34. package/dist/jobs/database/smtp-email-subscriber-database.service.js +6 -3
  35. package/dist/jobs/database/smtp-email-subscriber-database.service.js.map +1 -1
  36. package/dist/jobs/database/test-queue-subscriber-database.service.d.ts +3 -1
  37. package/dist/jobs/database/test-queue-subscriber-database.service.d.ts.map +1 -1
  38. package/dist/jobs/database/test-queue-subscriber-database.service.js +6 -3
  39. package/dist/jobs/database/test-queue-subscriber-database.service.js.map +1 -1
  40. package/dist/jobs/database/trigger-mcp-client-subscriber-database.service.d.ts +3 -1
  41. package/dist/jobs/database/trigger-mcp-client-subscriber-database.service.d.ts.map +1 -1
  42. package/dist/jobs/database/trigger-mcp-client-subscriber-database.service.js +5 -2
  43. package/dist/jobs/database/trigger-mcp-client-subscriber-database.service.js.map +1 -1
  44. package/dist/jobs/database/twilio-sms-publisher-database.service.d.ts +11 -0
  45. package/dist/jobs/database/twilio-sms-publisher-database.service.d.ts.map +1 -0
  46. package/dist/jobs/database/twilio-sms-publisher-database.service.js +39 -0
  47. package/dist/jobs/database/twilio-sms-publisher-database.service.js.map +1 -0
  48. package/dist/jobs/database/twilio-sms-queue-database-options.d.ts +8 -0
  49. package/dist/jobs/database/twilio-sms-queue-database-options.d.ts.map +1 -0
  50. package/dist/jobs/database/twilio-sms-queue-database-options.js +10 -0
  51. package/dist/jobs/database/twilio-sms-queue-database-options.js.map +1 -0
  52. package/dist/jobs/database/twilio-sms-subscriber-database.service.d.ts +17 -0
  53. package/dist/jobs/database/twilio-sms-subscriber-database.service.d.ts.map +1 -0
  54. package/dist/jobs/database/twilio-sms-subscriber-database.service.js +48 -0
  55. package/dist/jobs/database/twilio-sms-subscriber-database.service.js.map +1 -0
  56. package/dist/jobs/database/whatsapp-subscriber-database.service.d.ts +3 -1
  57. package/dist/jobs/database/whatsapp-subscriber-database.service.d.ts.map +1 -1
  58. package/dist/jobs/database/whatsapp-subscriber-database.service.js +6 -3
  59. package/dist/jobs/database/whatsapp-subscriber-database.service.js.map +1 -1
  60. package/dist/jobs/sms-subscriber.service.d.ts +1 -1
  61. package/dist/jobs/sms-subscriber.service.js +1 -1
  62. package/dist/jobs/sms-subscriber.service.js.map +1 -1
  63. package/dist/jobs/smtp-email-subscriber.service.d.ts +1 -1
  64. package/dist/seeders/module-metadata-seeder.service.d.ts +1 -1
  65. package/dist/seeders/module-metadata-seeder.service.d.ts.map +1 -1
  66. package/dist/seeders/module-metadata-seeder.service.js +15 -4
  67. package/dist/seeders/module-metadata-seeder.service.js.map +1 -1
  68. package/dist/services/mail/smtp-email.service.d.ts +4 -4
  69. package/dist/services/mail/smtp-email.service.d.ts.map +1 -1
  70. package/dist/services/mail/smtp-email.service.js +12 -8
  71. package/dist/services/mail/smtp-email.service.js.map +1 -1
  72. package/dist/services/poller.service.d.ts +24 -0
  73. package/dist/services/poller.service.d.ts.map +1 -0
  74. package/dist/services/poller.service.js +131 -0
  75. package/dist/services/poller.service.js.map +1 -0
  76. package/dist/services/queues/database-subscriber.service.d.ts +4 -1
  77. package/dist/services/queues/database-subscriber.service.d.ts.map +1 -1
  78. package/dist/services/queues/database-subscriber.service.js +13 -13
  79. package/dist/services/queues/database-subscriber.service.js.map +1 -1
  80. package/dist/services/sms/Msg91BaseSMSService.d.ts +2 -2
  81. package/dist/services/sms/Msg91BaseSMSService.d.ts.map +1 -1
  82. package/dist/services/sms/Msg91BaseSMSService.js.map +1 -1
  83. package/dist/services/sms/Msg91OTPService.d.ts +1 -1
  84. package/dist/services/sms/Msg91OTPService.d.ts.map +1 -1
  85. package/dist/services/sms/Msg91OTPService.js.map +1 -1
  86. package/dist/services/sms/Msg91SMSService.d.ts +1 -1
  87. package/dist/services/sms/Msg91SMSService.d.ts.map +1 -1
  88. package/dist/services/sms/Msg91SMSService.js.map +1 -1
  89. package/dist/services/sms/TwilioSMSService.d.ts +18 -0
  90. package/dist/services/sms/TwilioSMSService.d.ts.map +1 -0
  91. package/dist/services/sms/TwilioSMSService.js +115 -0
  92. package/dist/services/sms/TwilioSMSService.js.map +1 -0
  93. package/dist/solid-core.module.d.ts.map +1 -1
  94. package/dist/solid-core.module.js +10 -0
  95. package/dist/solid-core.module.js.map +1 -1
  96. package/dist/tsconfig.tsbuildinfo +1 -1
  97. package/package.json +4 -3
  98. package/src/config/common.config.ts +5 -0
  99. package/src/index.ts +2 -0
  100. package/src/interfaces.ts +5 -5
  101. package/src/jobs/database/api-email-subscriber-database.service.ts +3 -1
  102. package/src/jobs/database/computed-field-evaluation-subscriber.service.ts +4 -2
  103. package/src/jobs/database/generate-code-subscriber-database.service.ts +3 -1
  104. package/src/jobs/database/otp-subscriber-database.service.ts +3 -1
  105. package/src/jobs/database/sms-subscriber-database.service.ts +4 -2
  106. package/src/jobs/database/smtp-email-subscriber-database.service.ts +3 -1
  107. package/src/jobs/database/test-queue-subscriber-database.service.ts +3 -1
  108. package/src/jobs/database/trigger-mcp-client-subscriber-database.service.ts +3 -1
  109. package/src/jobs/database/twilio-sms-publisher-database.service.ts +23 -0
  110. package/src/jobs/database/twilio-sms-queue-database-options.ts +9 -0
  111. package/src/jobs/database/twilio-sms-subscriber-database.service.ts +32 -0
  112. package/src/jobs/database/whatsapp-subscriber-database.service.ts +3 -1
  113. package/src/jobs/sms-subscriber.service.ts +1 -1
  114. package/src/seeders/module-metadata-seeder.service.ts +18 -15
  115. package/src/services/mail/smtp-email.service.ts +18 -17
  116. package/src/services/poller.service.ts +163 -0
  117. package/src/services/queues/database-subscriber.service.ts +39 -12
  118. package/src/services/sms/Msg91BaseSMSService.ts +2 -2
  119. package/src/services/sms/Msg91OTPService.ts +1 -1
  120. package/src/services/sms/Msg91SMSService.ts +1 -1
  121. package/src/services/sms/TwilioSMSService.ts +118 -0
  122. package/src/solid-core.module.ts +13 -0
@@ -0,0 +1,163 @@
1
+ // src/common/poller/poller.service.ts
2
+ import {
3
+ Injectable,
4
+ Logger,
5
+ OnModuleDestroy,
6
+ BeforeApplicationShutdown,
7
+ } from '@nestjs/common';
8
+
9
+ export interface PollOptions {
10
+ /** Wait after a successful iteration */
11
+ baseDelayMs?: number; // default 1000
12
+ /** Maximum delay after repeated failures */
13
+ maxDelayMs?: number; // default 30000
14
+ /** Per-iteration timeout guard */
15
+ timeoutPerIterationMs?: number; // default 60000
16
+ /** Add jitter to spread load */
17
+ jitter?: boolean; // default true
18
+ }
19
+
20
+ type ProcessNextFn = (queueName: string) => Promise<unknown>;
21
+
22
+ interface PollerState {
23
+ queueName: string;
24
+ processNext: ProcessNextFn;
25
+ opts: Required<PollOptions>;
26
+ inFlight: boolean;
27
+ stopped: boolean;
28
+ backoff: number;
29
+ nextTimer?: NodeJS.Timeout;
30
+ }
31
+
32
+ @Injectable()
33
+ export class PollerService implements OnModuleDestroy, BeforeApplicationShutdown {
34
+ private readonly logger = new Logger(PollerService.name);
35
+ private readonly pollers = new Map<string, PollerState>();
36
+
37
+ start(queueName: string, processNext: ProcessNextFn, options: PollOptions = {}): void {
38
+ if (this.pollers.has(queueName)) {
39
+ this.logger.warn(`Poller "${queueName}" already started; ignoring.`);
40
+ return;
41
+ }
42
+
43
+ const opts: Required<PollOptions> = {
44
+ baseDelayMs: options.baseDelayMs ?? 1000,
45
+ maxDelayMs: options.maxDelayMs ?? 30_000,
46
+ timeoutPerIterationMs: options.timeoutPerIterationMs ?? 60_000,
47
+ jitter: options.jitter ?? true,
48
+ };
49
+
50
+ const state: PollerState = {
51
+ queueName,
52
+ processNext,
53
+ opts,
54
+ inFlight: false,
55
+ stopped: false,
56
+ backoff: opts.baseDelayMs,
57
+ nextTimer: undefined,
58
+ };
59
+
60
+ this.pollers.set(queueName, state);
61
+ // kick off on next tick
62
+ setImmediate(() => this.poll(state).catch(() => { }));
63
+ this.logger.log(`Started poller "${queueName}"`);
64
+ }
65
+
66
+ stop(queueName: string): void {
67
+ const state = this.pollers.get(queueName);
68
+ if (!state) return;
69
+
70
+ state.stopped = true;
71
+ if (state.nextTimer) {
72
+ clearTimeout(state.nextTimer);
73
+ state.nextTimer = undefined;
74
+ }
75
+ this.pollers.delete(queueName);
76
+ this.logger.log(`Stopped poller "${queueName}"`);
77
+ }
78
+
79
+ stopAll(): void {
80
+ for (const name of Array.from(this.pollers.keys())) {
81
+ this.stop(name);
82
+ }
83
+ }
84
+
85
+ async onModuleDestroy(): Promise<void> {
86
+ this.stopAll();
87
+ }
88
+
89
+ async beforeApplicationShutdown(): Promise<void> {
90
+ this.stopAll();
91
+ }
92
+
93
+ // ---- internals ----
94
+
95
+ private async poll(state: PollerState): Promise<void> {
96
+ if (state.stopped || state.inFlight) return;
97
+ state.inFlight = true;
98
+
99
+ try {
100
+ await this.withTimeout(
101
+ state.processNext(state.queueName),
102
+ state.opts.timeoutPerIterationMs,
103
+ );
104
+
105
+ // success: reset backoff and schedule next run after base delay
106
+ state.backoff = state.opts.baseDelayMs;
107
+ // this.logger.debug(`[${state.queueName}] iteration completed`);
108
+ this.schedule(state, state.opts.baseDelayMs);
109
+ } catch (err: unknown) {
110
+ const msg = this.errorToString(err);
111
+ this.logger.error(`[${state.queueName}] iteration failed: ${msg}`);
112
+
113
+ // failure: schedule with backoff + optional jitter, then increase backoff
114
+ const wait = this.computeWait(state.backoff, state.opts);
115
+ state.backoff = Math.min(state.backoff * 2, state.opts.maxDelayMs);
116
+ this.schedule(state, wait);
117
+ } finally {
118
+ state.inFlight = false;
119
+ }
120
+ }
121
+
122
+ private schedule(state: PollerState, delayMs: number) {
123
+ if (state.stopped) return;
124
+ if (state.nextTimer) clearTimeout(state.nextTimer);
125
+
126
+ state.nextTimer = setTimeout(() => {
127
+ // clear reference before calling poll to avoid re-entrancy confusion
128
+ state.nextTimer = undefined;
129
+ this.poll(state).catch(() => { });
130
+ }, delayMs);
131
+ }
132
+
133
+ private computeWait(currentBackoff: number, opts: Required<PollOptions>): number {
134
+ if (!opts.jitter) return currentBackoff;
135
+ // Full jitter: random in [250ms, currentBackoff * 2], clamped to maxDelayMs
136
+ const doubled = Math.min(currentBackoff * 2, opts.maxDelayMs);
137
+ const jittered = Math.floor(Math.random() * doubled);
138
+ return Math.max(250, jittered);
139
+ }
140
+
141
+ private async withTimeout<T>(p: Promise<T>, ms: number): Promise<T> {
142
+ let timer: NodeJS.Timeout | undefined;
143
+ try {
144
+ return await Promise.race<T>([
145
+ p,
146
+ new Promise<never>((_, rej) => {
147
+ timer = setTimeout(() => rej(new Error(`Iteration timed out after ${ms} ms`)), ms);
148
+ }),
149
+ ]);
150
+ } finally {
151
+ if (timer) clearTimeout(timer);
152
+ }
153
+ }
154
+
155
+ private errorToString(err: unknown): string {
156
+ if (err instanceof Error) return err.stack ?? err.message;
157
+ try {
158
+ return JSON.stringify(err);
159
+ } catch {
160
+ return String(err);
161
+ }
162
+ }
163
+ }
@@ -3,6 +3,7 @@ import { QueuesModuleOptions } from "../../interfaces";
3
3
  import { QueueMessage, QueueSubscriber } from '../../interfaces/mq';
4
4
  import { MqMessageQueueService } from '../mq-message-queue.service';
5
5
  import { MqMessageService } from '../mq-message.service';
6
+ import { PollerService } from '../poller.service';
6
7
 
7
8
 
8
9
  export abstract class DatabaseSubscriber<T> implements OnModuleInit, QueueSubscriber<T> {
@@ -13,6 +14,7 @@ export abstract class DatabaseSubscriber<T> implements OnModuleInit, QueueSubscr
13
14
  constructor(
14
15
  protected readonly mqMessageService: MqMessageService,
15
16
  protected readonly mqMessageQueueService: MqMessageQueueService,
17
+ protected readonly poller: PollerService,
16
18
  ) {
17
19
  this.serviceRole = process.env.QUEUES_SERVICE_ROLE;
18
20
  if (!this.serviceRole) {
@@ -70,6 +72,31 @@ export abstract class DatabaseSubscriber<T> implements OnModuleInit, QueueSubscr
70
72
  // this.logger.debug(`#### DatabaseSubscriber finished processing message from queue: ${queueName}`);
71
73
  }
72
74
 
75
+ // async onModuleInit(): Promise<void> {
76
+ // // we will start subscriber only if the current service role is subscriber.
77
+ // if (['both', 'subscriber'].includes(this.serviceRole)) {
78
+
79
+ // const options = this.options();
80
+
81
+ // const queueName = options.queueName;
82
+ // // setInterval(() => this.processNext(queueName), 1000);
83
+ // const poll = async () => {
84
+ // try {
85
+ // await this.processNext(queueName);
86
+ // } catch (err) {
87
+ // this.logger.error(`Polling error: ${err.message}`);
88
+ // } finally {
89
+ // setTimeout(poll, 1000); // Wait 1s *after* processing finishes
90
+ // }
91
+ // };
92
+
93
+ // // start the loop
94
+ // poll();
95
+
96
+ // this.logger.log(`DatabaseSubscriber ready to consume messages: ${JSON.stringify(this.options())}`);
97
+ // }
98
+ // }
99
+
73
100
  async onModuleInit(): Promise<void> {
74
101
  // we will start subscriber only if the current service role is subscriber.
75
102
  if (['both', 'subscriber'].includes(this.serviceRole)) {
@@ -77,24 +104,24 @@ export abstract class DatabaseSubscriber<T> implements OnModuleInit, QueueSubscr
77
104
  const options = this.options();
78
105
 
79
106
  const queueName = options.queueName;
80
- // setInterval(() => this.processNext(queueName), 1000);
81
- const poll = async () => {
82
- try {
83
- await this.processNext(queueName);
84
- } catch (err) {
85
- this.logger.error(`Polling error: ${err.message}`);
86
- } finally {
87
- setTimeout(poll, 1000); // Wait 1s *after* processing finishes
88
- }
89
- };
90
107
 
91
- // start the loop
92
- poll();
108
+ this.poller.start(queueName, (q) => this.processNext(q), {
109
+ baseDelayMs: 1000,
110
+ maxDelayMs: 30_000,
111
+ timeoutPerIterationMs: 60_000,
112
+ jitter: true,
113
+ });
93
114
 
94
115
  this.logger.log(`DatabaseSubscriber ready to consume messages: ${JSON.stringify(this.options())}`);
95
116
  }
96
117
  }
97
118
 
119
+ onModuleDestroy() {
120
+ const options = this.options();
121
+ const queueName = options.queueName;
122
+ this.poller.stop(queueName);
123
+ }
124
+
98
125
  /**
99
126
  * Abstract method for message processing logic.
100
127
  */
@@ -20,7 +20,7 @@ export abstract class Msg91BaseSMSService implements ISMS {
20
20
  throw new Error(`Msg91 does not support sending plain text messages, you need to register a template and use the templateId to send the SMS.`);
21
21
  }
22
22
 
23
- async sendSMSUsingTemplate(to: string, templateName: string, templateParams: any, shouldQueueSms = false): Promise<void> {
23
+ async sendSMSUsingTemplate(to: string, templateName: string, templateParams: any, shouldQueueSms = false): Promise<any> {
24
24
  // Load template and evaluate it.
25
25
  const emailTemplate = await this.smsTemplateService.findOneByName(templateName);
26
26
  if (!emailTemplate) {
@@ -76,5 +76,5 @@ export abstract class Msg91BaseSMSService implements ISMS {
76
76
  this.logger.debug(`Queueing SMS to ${to} with message ${JSON.stringify(message)}`);
77
77
  }
78
78
 
79
- abstract sendSMSSynchronously(message: QueueMessage<any>): Promise<void>
79
+ abstract sendSMSSynchronously(message: QueueMessage<any>): Promise<any>
80
80
  }
@@ -28,7 +28,7 @@ export class Msg91OTPService extends Msg91BaseSMSService implements ISMS {
28
28
  super(commonConfiguration, 'OTPQueuePublisher', publisherFactory, smsTemplateService);
29
29
  }
30
30
 
31
- async sendSMSSynchronously(message: QueueMessage<any>): Promise<void> {
31
+ async sendSMSSynchronously(message: QueueMessage<any>): Promise<any> {
32
32
  const { to, templateId, otp } = message.payload;
33
33
  const params = { otp, template_id: templateId, mobile: to, authkey: this.commonConfiguration.msg91Sms.apiKey }
34
34
  const otpUrl = `${this.commonConfiguration.msg91Sms.url}/otp?${this.paramsToQueryString(params)}`;
@@ -21,7 +21,7 @@ export class Msg91SMSService extends Msg91BaseSMSService implements ISMS {
21
21
  super(commonConfiguration, 'SmsQueuePublisher', publisherFactory, smsTemplateService)
22
22
  }
23
23
 
24
- async sendSMSSynchronously(message: QueueMessage<any>): Promise<void> {
24
+ async sendSMSSynchronously(message: QueueMessage<any>): Promise<any> {
25
25
  const { to, templateId, ...templateParams } = message.payload;
26
26
  const body = { template_id: templateId, short_url: "0", recipients: [{ mobiles: to, ...templateParams }] };
27
27
  const headers = { "authkey": this.commonConfiguration.msg91Sms.apiKey };
@@ -0,0 +1,118 @@
1
+ import Handlebars from "handlebars";
2
+ import { Inject, Injectable, Logger } from "@nestjs/common";
3
+ import { ConfigType } from "@nestjs/config";
4
+ import commonConfig from "src/config/common.config";
5
+ import { SmsTemplateService } from "../sms-template.service";
6
+ import { ISMS } from "../../interfaces";
7
+ import { PublisherFactory } from "../queues/publisher-factory.service";
8
+ import twilio from 'twilio';
9
+ import { QueueMessage } from "src/interfaces/mq";
10
+
11
+
12
+ @Injectable()
13
+ export class TwilioSMSService implements ISMS {
14
+ private readonly logger = new Logger(TwilioSMSService.name);
15
+
16
+ constructor(
17
+ @Inject(commonConfig.KEY)
18
+ private commonConfiguration: ConfigType<typeof commonConfig>,
19
+ private publisherFactory: PublisherFactory<any>,
20
+ private smsTemplateService: SmsTemplateService,
21
+ ) {
22
+ // super(commonConfiguration, 'OTPQueuePublisher', publisherFactory, smsTemplateService);
23
+ }
24
+
25
+ async sendSMS(to: string, body: string, shouldQueueSms: boolean): Promise<any> {
26
+ const accountSid = this.commonConfiguration.twilio.accountSid;
27
+ const authToken = this.commonConfiguration.twilio.authToken;
28
+ const twilioNumber = this.commonConfiguration.twilio.number;
29
+ if (!accountSid || !authToken || !twilioNumber) {
30
+ throw new Error("Missing COMMON_TWILIO_ACCOUNT_SID or COMMON_TWILIO_AUTH_TOKEN or COMMON_TWILIO_NUMBER in env.");
31
+ }
32
+
33
+ const message = {
34
+ payload: {
35
+ body: body,
36
+ to: to,
37
+ },
38
+ };
39
+
40
+ // Send using queue if the developer has explicitly invoked with true.
41
+ if (shouldQueueSms === true) {
42
+ await this.sendSMSAsynchronously(message);
43
+ }
44
+ // If developer has not, however system config mandates that we send using queue, still we send.
45
+ else if (shouldQueueSms === false && this.commonConfiguration.shouldQueueSms === true) {
46
+ await this.sendSMSAsynchronously(message);
47
+ }
48
+ // Else we send synch
49
+ else {
50
+ await this.sendSMSSynchronously(message);
51
+ }
52
+
53
+ return message;
54
+ }
55
+
56
+ async sendSMSUsingTemplate(to: string, templateName: string, templateParams: any, shouldQueueSms: boolean): Promise<any> {
57
+ // Load template and evaluate it.
58
+ const smsTemplate = await this.smsTemplateService.findOneByName(templateName);
59
+ if (!smsTemplate) {
60
+ throw new Error(`Invalid template name ${templateName}`);
61
+ }
62
+
63
+ // Evaluate the body template.
64
+ let body = '';
65
+ try {
66
+ const bodyTemplate = Handlebars.compile(smsTemplate.body);
67
+ body = bodyTemplate(templateParams);
68
+ } catch (error) {
69
+ throw new Error('Unable to compile sms template body');
70
+ }
71
+ // Finally send the email.
72
+ return await this.sendSMS(to, body, shouldQueueSms);
73
+
74
+ }
75
+
76
+ async sendSMSAsynchronously(message) {
77
+ const { to } = message.payload;
78
+ this.publisherFactory.publish(message, 'TwilioSmsQueuePublisher');
79
+ this.logger.debug(`Queueing SMS to ${to} with message ${JSON.stringify(message)}`);
80
+ }
81
+
82
+ async sendSMSSynchronously(message: QueueMessage<any>): Promise<any> {
83
+ const accountSid = this.commonConfiguration.twilio.accountSid;
84
+ const authToken = this.commonConfiguration.twilio.authToken;
85
+ const twilioNumber = this.commonConfiguration.twilio.number;
86
+ if (!accountSid || !authToken || !twilioNumber) {
87
+ throw new Error("Missing COMMON_TWILIO_ACCOUNT_SID or COMMON_TWILIO_AUTH_TOKEN or COMMON_TWILIO_NUMBER in env.");
88
+ }
89
+
90
+ const { to, body } = message.payload;
91
+
92
+ const client = twilio(accountSid, authToken);
93
+ try {
94
+ const toSplit = to.split(',');
95
+
96
+ const r = [];
97
+
98
+ for (let i = 0; i < toSplit.length; i++) {
99
+ const actualTo = toSplit[i];
100
+ const twilioResponseMsg = await client.messages.create({
101
+ body: body,
102
+ from: twilioNumber,
103
+ to: actualTo,
104
+ });
105
+
106
+ this.logger.debug(`Sending SMS to ${actualTo} using Twilio`);
107
+ this.logger.debug(`Twilio response: `);
108
+ this.logger.debug(JSON.stringify(twilioResponseMsg))
109
+
110
+ r.push(twilioResponseMsg);
111
+ }
112
+
113
+ return r;
114
+ } catch (error) {
115
+ throw new Error(error);
116
+ }
117
+ }
118
+ }
@@ -186,6 +186,11 @@ import { OTPQueuePublisherDatabase } from './jobs/database/otp-publisher-databas
186
186
  import { OTPQueueSubscriberDatabase } from './jobs/database/otp-subscriber-database.service';
187
187
  import { SmsQueuePublisherDatabase } from './jobs/database/sms-publisher-database.service';
188
188
  import { SmsQueueSubscriberDatabase } from './jobs/database/sms-subscriber-database.service';
189
+
190
+ import { TwilioSmsQueuePublisherDatabase } from './jobs/database/twilio-sms-publisher-database.service';
191
+ import { TwilioSmsQueueSubscriberDatabase } from './jobs/database/twilio-sms-subscriber-database.service';
192
+
193
+
189
194
  import { TriggerMcpClientPublisherDatabase } from './jobs/database/trigger-mcp-client-publisher-database.service';
190
195
  import { TriggerMcpClientSubscriberDatabase } from './jobs/database/trigger-mcp-client-subscriber-database.service';
191
196
  import { WhatsappQueuePublisherDatabase } from './jobs/database/whatsapp-publisher-database.service';
@@ -260,6 +265,8 @@ import { SolidCreateModelLayoutMcpToolResponseHandler } from './services/mcp-too
260
265
  import { NoopsEntityComputedFieldProviderService } from './services/computed-fields/entity/noops-entity-computed-field-provider.service';
261
266
  import { AlphaNumExternalIdComputationProvider } from './services/computed-fields/entity/alpha-num-external-id-computed-field-provider';
262
267
  import { MailFactory } from './factories/mail.factory';
268
+ import { TwilioSMSService } from './services/sms/TwilioSMSService';
269
+ import { PollerService } from './services/poller.service';
263
270
 
264
271
 
265
272
  @Global()
@@ -427,9 +434,11 @@ import { MailFactory } from './factories/mail.factory';
427
434
  Msg91SMSService,
428
435
  Msg91OTPService,
429
436
  Msg91WhatsappService,
437
+ TwilioSMSService,
430
438
  SmsTemplateService,
431
439
  EmailTemplateService,
432
440
  PublisherFactory,
441
+ PollerService,
433
442
 
434
443
  McpToolResponseHandlerFactory,
435
444
  SolidCreateModuleMcpToolResponseHandler,
@@ -449,6 +458,8 @@ import { MailFactory } from './factories/mail.factory';
449
458
  SmsQueueSubscriber,
450
459
  SmsQueuePublisherDatabase,
451
460
  SmsQueueSubscriberDatabase,
461
+ TwilioSmsQueuePublisherDatabase,
462
+ TwilioSmsQueueSubscriberDatabase,
452
463
  OTPQueuePublisher,
453
464
  OTPQueueSubscriber,
454
465
  OTPQueuePublisherDatabase,
@@ -567,6 +578,7 @@ import { MailFactory } from './factories/mail.factory';
567
578
  ElasticEmailService,
568
579
  Msg91SMSService,
569
580
  Msg91OTPService,
581
+ TwilioSMSService,
570
582
  Msg91WhatsappService,
571
583
  TinyUrlService,
572
584
  PdfService,
@@ -592,6 +604,7 @@ import { MailFactory } from './factories/mail.factory';
592
604
  ConfigModule,
593
605
  PublisherFactory,
594
606
  MailFactory,
607
+ PollerService
595
608
  ],
596
609
  })
597
610
  export class SolidCoreModule { }