@stacksjs/ts-cloud-core 0.1.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.
Files changed (251) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +321 -0
  3. package/package.json +31 -0
  4. package/src/advanced-features.test.ts +465 -0
  5. package/src/aws/cloudformation.ts +421 -0
  6. package/src/aws/cloudfront.ts +158 -0
  7. package/src/aws/credentials.test.ts +132 -0
  8. package/src/aws/credentials.ts +545 -0
  9. package/src/aws/index.ts +87 -0
  10. package/src/aws/s3.test.ts +188 -0
  11. package/src/aws/s3.ts +1088 -0
  12. package/src/aws/signature.test.ts +670 -0
  13. package/src/aws/signature.ts +1155 -0
  14. package/src/backup/disaster-recovery.test.ts +726 -0
  15. package/src/backup/disaster-recovery.ts +500 -0
  16. package/src/backup/index.ts +34 -0
  17. package/src/backup/manager.test.ts +498 -0
  18. package/src/backup/manager.ts +432 -0
  19. package/src/cicd/circleci.ts +430 -0
  20. package/src/cicd/github-actions.ts +424 -0
  21. package/src/cicd/gitlab-ci.ts +255 -0
  22. package/src/cicd/index.ts +8 -0
  23. package/src/cli/history.ts +396 -0
  24. package/src/cli/index.ts +10 -0
  25. package/src/cli/progress.ts +458 -0
  26. package/src/cli/repl.ts +454 -0
  27. package/src/cli/suggestions.ts +327 -0
  28. package/src/cli/table.test.ts +319 -0
  29. package/src/cli/table.ts +332 -0
  30. package/src/cloudformation/builder.test.ts +327 -0
  31. package/src/cloudformation/builder.ts +378 -0
  32. package/src/cloudformation/builders/api-gateway.ts +449 -0
  33. package/src/cloudformation/builders/cache.ts +334 -0
  34. package/src/cloudformation/builders/cdn.ts +278 -0
  35. package/src/cloudformation/builders/compute.ts +485 -0
  36. package/src/cloudformation/builders/database.ts +392 -0
  37. package/src/cloudformation/builders/functions.ts +343 -0
  38. package/src/cloudformation/builders/messaging.ts +140 -0
  39. package/src/cloudformation/builders/monitoring.ts +300 -0
  40. package/src/cloudformation/builders/network.ts +264 -0
  41. package/src/cloudformation/builders/queue.ts +147 -0
  42. package/src/cloudformation/builders/security.ts +399 -0
  43. package/src/cloudformation/builders/storage.ts +285 -0
  44. package/src/cloudformation/index.ts +30 -0
  45. package/src/cloudformation/types.ts +173 -0
  46. package/src/compliance/aws-config.ts +543 -0
  47. package/src/compliance/cloudtrail.ts +376 -0
  48. package/src/compliance/compliance.test.ts +423 -0
  49. package/src/compliance/guardduty.ts +446 -0
  50. package/src/compliance/index.ts +66 -0
  51. package/src/compliance/security-hub.ts +456 -0
  52. package/src/containers/build-optimization.ts +416 -0
  53. package/src/containers/containers.test.ts +508 -0
  54. package/src/containers/image-scanning.ts +360 -0
  55. package/src/containers/index.ts +9 -0
  56. package/src/containers/registry.ts +293 -0
  57. package/src/containers/service-mesh.ts +520 -0
  58. package/src/database/database.test.ts +762 -0
  59. package/src/database/index.ts +9 -0
  60. package/src/database/migrations.ts +444 -0
  61. package/src/database/performance.ts +528 -0
  62. package/src/database/replicas.ts +534 -0
  63. package/src/database/users.ts +494 -0
  64. package/src/dependency-graph.ts +143 -0
  65. package/src/deployment/ab-testing.ts +582 -0
  66. package/src/deployment/blue-green.ts +452 -0
  67. package/src/deployment/canary.ts +500 -0
  68. package/src/deployment/deployment.test.ts +526 -0
  69. package/src/deployment/index.ts +61 -0
  70. package/src/deployment/progressive.ts +62 -0
  71. package/src/dns/dns.test.ts +641 -0
  72. package/src/dns/dnssec.ts +315 -0
  73. package/src/dns/index.ts +8 -0
  74. package/src/dns/resolver.ts +496 -0
  75. package/src/dns/routing.ts +593 -0
  76. package/src/email/advanced/analytics.ts +445 -0
  77. package/src/email/advanced/index.ts +11 -0
  78. package/src/email/advanced/rules.ts +465 -0
  79. package/src/email/advanced/scheduling.ts +352 -0
  80. package/src/email/advanced/search.ts +412 -0
  81. package/src/email/advanced/shared-mailboxes.ts +404 -0
  82. package/src/email/advanced/templates.ts +455 -0
  83. package/src/email/advanced/threading.ts +281 -0
  84. package/src/email/analytics.ts +467 -0
  85. package/src/email/bounce-handling.ts +425 -0
  86. package/src/email/email.test.ts +431 -0
  87. package/src/email/handlers/__tests__/inbound.test.ts +38 -0
  88. package/src/email/handlers/__tests__/outbound.test.ts +37 -0
  89. package/src/email/handlers/converter.ts +227 -0
  90. package/src/email/handlers/feedback.ts +228 -0
  91. package/src/email/handlers/inbound.ts +169 -0
  92. package/src/email/handlers/outbound.ts +178 -0
  93. package/src/email/index.ts +15 -0
  94. package/src/email/reputation.ts +303 -0
  95. package/src/email/templates.ts +352 -0
  96. package/src/errors/index.test.ts +434 -0
  97. package/src/errors/index.ts +416 -0
  98. package/src/health-checks/index.ts +40 -0
  99. package/src/index.ts +360 -0
  100. package/src/intrinsic-functions.ts +118 -0
  101. package/src/lambda/concurrency.ts +330 -0
  102. package/src/lambda/destinations.ts +345 -0
  103. package/src/lambda/dlq.ts +425 -0
  104. package/src/lambda/index.ts +11 -0
  105. package/src/lambda/lambda.test.ts +840 -0
  106. package/src/lambda/layers.ts +263 -0
  107. package/src/lambda/versions.ts +376 -0
  108. package/src/lambda/vpc.ts +399 -0
  109. package/src/local/config.ts +114 -0
  110. package/src/local/index.ts +6 -0
  111. package/src/local/mock-aws.ts +351 -0
  112. package/src/modules/ai.ts +340 -0
  113. package/src/modules/api.ts +478 -0
  114. package/src/modules/auth.ts +805 -0
  115. package/src/modules/cache.ts +417 -0
  116. package/src/modules/cdn.ts +1062 -0
  117. package/src/modules/communication.ts +1094 -0
  118. package/src/modules/compute.ts +3348 -0
  119. package/src/modules/database.ts +554 -0
  120. package/src/modules/deployment.ts +1079 -0
  121. package/src/modules/dns.ts +337 -0
  122. package/src/modules/email.ts +1538 -0
  123. package/src/modules/filesystem.ts +515 -0
  124. package/src/modules/index.ts +32 -0
  125. package/src/modules/messaging.ts +486 -0
  126. package/src/modules/monitoring.ts +2086 -0
  127. package/src/modules/network.ts +664 -0
  128. package/src/modules/parameter-store.ts +325 -0
  129. package/src/modules/permissions.ts +1081 -0
  130. package/src/modules/phone.ts +494 -0
  131. package/src/modules/queue.ts +1260 -0
  132. package/src/modules/redirects.ts +464 -0
  133. package/src/modules/registry.ts +699 -0
  134. package/src/modules/search.ts +401 -0
  135. package/src/modules/secrets.ts +416 -0
  136. package/src/modules/security.ts +731 -0
  137. package/src/modules/sms.ts +389 -0
  138. package/src/modules/storage.ts +1120 -0
  139. package/src/modules/workflow.ts +680 -0
  140. package/src/multi-account/config.ts +521 -0
  141. package/src/multi-account/index.ts +7 -0
  142. package/src/multi-account/manager.ts +427 -0
  143. package/src/multi-region/cross-region.ts +410 -0
  144. package/src/multi-region/index.ts +8 -0
  145. package/src/multi-region/manager.ts +483 -0
  146. package/src/multi-region/regions.ts +435 -0
  147. package/src/network-security/index.ts +48 -0
  148. package/src/observability/index.ts +9 -0
  149. package/src/observability/logs.ts +522 -0
  150. package/src/observability/metrics.ts +460 -0
  151. package/src/observability/observability.test.ts +782 -0
  152. package/src/observability/synthetics.ts +568 -0
  153. package/src/observability/xray.ts +358 -0
  154. package/src/phone/advanced/analytics.ts +349 -0
  155. package/src/phone/advanced/callbacks.ts +428 -0
  156. package/src/phone/advanced/index.ts +8 -0
  157. package/src/phone/advanced/ivr-builder.ts +504 -0
  158. package/src/phone/advanced/recording.ts +310 -0
  159. package/src/phone/handlers/__tests__/incoming-call.test.ts +40 -0
  160. package/src/phone/handlers/incoming-call.ts +117 -0
  161. package/src/phone/handlers/missed-call.ts +116 -0
  162. package/src/phone/handlers/voicemail.ts +179 -0
  163. package/src/phone/index.ts +9 -0
  164. package/src/presets/api-backend.ts +134 -0
  165. package/src/presets/data-pipeline.ts +204 -0
  166. package/src/presets/extend.test.ts +295 -0
  167. package/src/presets/extend.ts +297 -0
  168. package/src/presets/fullstack-app.ts +144 -0
  169. package/src/presets/index.ts +27 -0
  170. package/src/presets/jamstack.ts +135 -0
  171. package/src/presets/microservices.ts +167 -0
  172. package/src/presets/ml-api.ts +208 -0
  173. package/src/presets/nodejs-server.ts +104 -0
  174. package/src/presets/nodejs-serverless.ts +114 -0
  175. package/src/presets/realtime-app.ts +184 -0
  176. package/src/presets/static-site.ts +64 -0
  177. package/src/presets/traditional-web-app.ts +339 -0
  178. package/src/presets/wordpress.ts +138 -0
  179. package/src/preview/github.test.ts +249 -0
  180. package/src/preview/github.ts +297 -0
  181. package/src/preview/index.ts +37 -0
  182. package/src/preview/manager.test.ts +440 -0
  183. package/src/preview/manager.ts +326 -0
  184. package/src/preview/notifications.test.ts +582 -0
  185. package/src/preview/notifications.ts +341 -0
  186. package/src/queue/batch-processing.ts +402 -0
  187. package/src/queue/dlq-monitoring.ts +402 -0
  188. package/src/queue/fifo.ts +342 -0
  189. package/src/queue/index.ts +9 -0
  190. package/src/queue/management.ts +428 -0
  191. package/src/queue/queue.test.ts +429 -0
  192. package/src/resource-mgmt/index.ts +39 -0
  193. package/src/resource-naming.ts +62 -0
  194. package/src/s3/index.ts +523 -0
  195. package/src/schema/cloud-config.schema.json +554 -0
  196. package/src/schema/index.ts +68 -0
  197. package/src/security/certificate-manager.ts +492 -0
  198. package/src/security/index.ts +9 -0
  199. package/src/security/scanning.ts +545 -0
  200. package/src/security/secrets-manager.ts +476 -0
  201. package/src/security/secrets-rotation.ts +456 -0
  202. package/src/security/security.test.ts +738 -0
  203. package/src/sms/advanced/ab-testing.ts +389 -0
  204. package/src/sms/advanced/analytics.ts +336 -0
  205. package/src/sms/advanced/campaigns.ts +523 -0
  206. package/src/sms/advanced/chatbot.ts +224 -0
  207. package/src/sms/advanced/index.ts +10 -0
  208. package/src/sms/advanced/link-tracking.ts +248 -0
  209. package/src/sms/advanced/mms.ts +308 -0
  210. package/src/sms/handlers/__tests__/send.test.ts +40 -0
  211. package/src/sms/handlers/delivery-status.ts +133 -0
  212. package/src/sms/handlers/receive.ts +162 -0
  213. package/src/sms/handlers/send.ts +174 -0
  214. package/src/sms/index.ts +9 -0
  215. package/src/stack-diff.ts +389 -0
  216. package/src/static-site/index.ts +85 -0
  217. package/src/template-builder.ts +110 -0
  218. package/src/template-validator.ts +574 -0
  219. package/src/utils/cache.ts +291 -0
  220. package/src/utils/diff.ts +269 -0
  221. package/src/utils/hash.ts +227 -0
  222. package/src/utils/index.ts +8 -0
  223. package/src/utils/parallel.ts +294 -0
  224. package/src/validators/credentials.test.ts +274 -0
  225. package/src/validators/credentials.ts +233 -0
  226. package/src/validators/quotas.test.ts +434 -0
  227. package/src/validators/quotas.ts +217 -0
  228. package/test/ai.test.ts +327 -0
  229. package/test/api.test.ts +511 -0
  230. package/test/auth.test.ts +632 -0
  231. package/test/cache.test.ts +406 -0
  232. package/test/cdn.test.ts +247 -0
  233. package/test/compute.test.ts +861 -0
  234. package/test/database.test.ts +523 -0
  235. package/test/deployment.test.ts +499 -0
  236. package/test/dns.test.ts +270 -0
  237. package/test/email.test.ts +439 -0
  238. package/test/filesystem.test.ts +382 -0
  239. package/test/integration.test.ts +350 -0
  240. package/test/messaging.test.ts +514 -0
  241. package/test/monitoring.test.ts +634 -0
  242. package/test/network.test.ts +425 -0
  243. package/test/permissions.test.ts +488 -0
  244. package/test/queue.test.ts +484 -0
  245. package/test/registry.test.ts +306 -0
  246. package/test/security.test.ts +462 -0
  247. package/test/storage.test.ts +463 -0
  248. package/test/template-validator.test.ts +559 -0
  249. package/test/workflow.test.ts +592 -0
  250. package/tsconfig.json +16 -0
  251. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,336 @@
1
+ /**
2
+ * SMS Analytics
3
+ *
4
+ * Provides delivery rates, engagement metrics, and reporting
5
+ */
6
+
7
+ export interface SmsMetrics {
8
+ period: string
9
+ sent: number
10
+ delivered: number
11
+ failed: number
12
+ pending: number
13
+ optedOut: number
14
+ deliveryRate: number
15
+ failureRate: number
16
+ averageDeliveryTime: number
17
+ cost: number
18
+ }
19
+
20
+ export interface SmsEngagement {
21
+ messageId: string
22
+ delivered: boolean
23
+ deliveredAt?: string
24
+ clicked?: boolean
25
+ clickedAt?: string
26
+ replied?: boolean
27
+ repliedAt?: string
28
+ replyContent?: string
29
+ optedOut?: boolean
30
+ optedOutAt?: string
31
+ }
32
+
33
+ export interface DeliveryReport {
34
+ messageId: string
35
+ to: string
36
+ status: 'PENDING' | 'SUCCESSFUL' | 'FAILED' | 'UNKNOWN'
37
+ statusCode?: string
38
+ statusMessage?: string
39
+ carrier?: string
40
+ countryCode?: string
41
+ priceInMillicents?: number
42
+ timestamp: string
43
+ }
44
+
45
+ /**
46
+ * SMS Analytics Module
47
+ */
48
+ export class SmsAnalytics {
49
+ /**
50
+ * Lambda code for analytics aggregation
51
+ */
52
+ static AnalyticsAggregatorCode = `
53
+ const { DynamoDBClient, ScanCommand, PutItemCommand, QueryCommand } = require('@aws-sdk/client-dynamodb');
54
+
55
+ const dynamodb = new DynamoDBClient({});
56
+ const MESSAGE_LOG_TABLE = process.env.MESSAGE_LOG_TABLE;
57
+ const ANALYTICS_TABLE = process.env.ANALYTICS_TABLE;
58
+
59
+ exports.handler = async (event) => {
60
+ console.log('SMS analytics aggregator event:', JSON.stringify(event, null, 2));
61
+
62
+ const now = new Date();
63
+ const hourAgo = new Date(now.getTime() - 60 * 60 * 1000);
64
+ const dayAgo = new Date(now.getTime() - 24 * 60 * 60 * 1000);
65
+
66
+ try {
67
+ // Get messages from the last hour
68
+ const hourlyResult = await dynamodb.send(new ScanCommand({
69
+ TableName: MESSAGE_LOG_TABLE,
70
+ FilterExpression: 'sentAt >= :hourAgo',
71
+ ExpressionAttributeValues: {
72
+ ':hourAgo': { S: hourAgo.toISOString() },
73
+ },
74
+ }));
75
+
76
+ const hourlyMessages = hourlyResult.Items || [];
77
+ const hourlyMetrics = calculateMetrics(hourlyMessages);
78
+
79
+ // Save hourly metrics
80
+ await dynamodb.send(new PutItemCommand({
81
+ TableName: ANALYTICS_TABLE,
82
+ Item: {
83
+ period: { S: \`hourly-\${now.toISOString().slice(0, 13)}\` },
84
+ type: { S: 'hourly' },
85
+ timestamp: { S: now.toISOString() },
86
+ metrics: { S: JSON.stringify(hourlyMetrics) },
87
+ ttl: { N: String(Math.floor(Date.now() / 1000) + 7 * 24 * 60 * 60) },
88
+ },
89
+ }));
90
+
91
+ // Get messages from the last day
92
+ const dailyResult = await dynamodb.send(new ScanCommand({
93
+ TableName: MESSAGE_LOG_TABLE,
94
+ FilterExpression: 'sentAt >= :dayAgo',
95
+ ExpressionAttributeValues: {
96
+ ':dayAgo': { S: dayAgo.toISOString() },
97
+ },
98
+ }));
99
+
100
+ const dailyMessages = dailyResult.Items || [];
101
+ const dailyMetrics = calculateMetrics(dailyMessages);
102
+
103
+ // Save daily metrics
104
+ await dynamodb.send(new PutItemCommand({
105
+ TableName: ANALYTICS_TABLE,
106
+ Item: {
107
+ period: { S: \`daily-\${now.toISOString().slice(0, 10)}\` },
108
+ type: { S: 'daily' },
109
+ timestamp: { S: now.toISOString() },
110
+ metrics: { S: JSON.stringify(dailyMetrics) },
111
+ ttl: { N: String(Math.floor(Date.now() / 1000) + 90 * 24 * 60 * 60) },
112
+ },
113
+ }));
114
+
115
+ // Calculate by country
116
+ const byCountry = {};
117
+ for (const msg of dailyMessages) {
118
+ const country = msg.countryCode?.S || 'UNKNOWN';
119
+ if (!byCountry[country]) {
120
+ byCountry[country] = [];
121
+ }
122
+ byCountry[country].push(msg);
123
+ }
124
+
125
+ for (const [country, messages] of Object.entries(byCountry)) {
126
+ const countryMetrics = calculateMetrics(messages);
127
+ await dynamodb.send(new PutItemCommand({
128
+ TableName: ANALYTICS_TABLE,
129
+ Item: {
130
+ period: { S: \`country-\${country}-\${now.toISOString().slice(0, 10)}\` },
131
+ type: { S: 'country' },
132
+ country: { S: country },
133
+ timestamp: { S: now.toISOString() },
134
+ metrics: { S: JSON.stringify(countryMetrics) },
135
+ ttl: { N: String(Math.floor(Date.now() / 1000) + 30 * 24 * 60 * 60) },
136
+ },
137
+ }));
138
+ }
139
+
140
+ console.log('SMS analytics aggregated successfully');
141
+ return { statusCode: 200 };
142
+ } catch (error) {
143
+ console.error('Error aggregating SMS analytics:', error);
144
+ return { statusCode: 500, error: error.message };
145
+ }
146
+ };
147
+
148
+ function calculateMetrics(messages) {
149
+ const sent = messages.length;
150
+ const delivered = messages.filter(m => m.deliveryStatus?.S === 'SUCCESSFUL').length;
151
+ const failed = messages.filter(m => ['FAILED', 'PERMANENT_FAILURE'].includes(m.deliveryStatus?.S)).length;
152
+ const pending = messages.filter(m => !m.deliveryStatus?.S || m.deliveryStatus?.S === 'PENDING').length;
153
+ const optedOut = messages.filter(m => m.deliveryStatus?.S === 'OPTED_OUT').length;
154
+
155
+ const deliveryTimes = messages
156
+ .filter(m => m.sentAt?.S && m.deliveredAt?.S)
157
+ .map(m => new Date(m.deliveredAt.S) - new Date(m.sentAt.S));
158
+
159
+ const averageDeliveryTime = deliveryTimes.length > 0
160
+ ? deliveryTimes.reduce((a, b) => a + b, 0) / deliveryTimes.length / 1000
161
+ : 0;
162
+
163
+ const cost = messages
164
+ .filter(m => m.priceMillicents?.N)
165
+ .reduce((sum, m) => sum + parseFloat(m.priceMillicents.N) / 100000, 0);
166
+
167
+ return {
168
+ sent,
169
+ delivered,
170
+ failed,
171
+ pending,
172
+ optedOut,
173
+ deliveryRate: sent > 0 ? Math.round((delivered / sent) * 1000) / 10 : 0,
174
+ failureRate: sent > 0 ? Math.round((failed / sent) * 1000) / 10 : 0,
175
+ averageDeliveryTime: Math.round(averageDeliveryTime * 10) / 10,
176
+ cost: Math.round(cost * 100) / 100,
177
+ };
178
+ }
179
+ `
180
+
181
+ /**
182
+ * Lambda code for real-time delivery tracking
183
+ */
184
+ static DeliveryTrackerCode = `
185
+ const { DynamoDBClient, UpdateItemCommand, PutItemCommand } = require('@aws-sdk/client-dynamodb');
186
+
187
+ const dynamodb = new DynamoDBClient({});
188
+ const MESSAGE_LOG_TABLE = process.env.MESSAGE_LOG_TABLE;
189
+ const DELIVERY_REPORTS_TABLE = process.env.DELIVERY_REPORTS_TABLE;
190
+
191
+ exports.handler = async (event) => {
192
+ console.log('Delivery tracker event:', JSON.stringify(event, null, 2));
193
+
194
+ for (const record of event.Records) {
195
+ try {
196
+ const message = JSON.parse(record.Sns?.Message || record.body || '{}');
197
+
198
+ const {
199
+ messageId,
200
+ destinationPhoneNumber,
201
+ messageStatus,
202
+ messageStatusDescription,
203
+ isoCountryCode,
204
+ mcc,
205
+ mnc,
206
+ priceInMillicentsUSD,
207
+ } = message;
208
+
209
+ if (!messageId) continue;
210
+
211
+ const now = new Date().toISOString();
212
+
213
+ // Update message log
214
+ await dynamodb.send(new UpdateItemCommand({
215
+ TableName: MESSAGE_LOG_TABLE,
216
+ Key: { messageId: { S: messageId } },
217
+ UpdateExpression: 'SET deliveryStatus = :status, deliveredAt = :now, countryCode = :country, priceMillicents = :price',
218
+ ExpressionAttributeValues: {
219
+ ':status': { S: messageStatus || 'UNKNOWN' },
220
+ ':now': { S: now },
221
+ ':country': { S: isoCountryCode || '' },
222
+ ':price': { N: String(priceInMillicentsUSD || 0) },
223
+ },
224
+ }));
225
+
226
+ // Save delivery report
227
+ await dynamodb.send(new PutItemCommand({
228
+ TableName: DELIVERY_REPORTS_TABLE,
229
+ Item: {
230
+ messageId: { S: messageId },
231
+ to: { S: destinationPhoneNumber || '' },
232
+ status: { S: messageStatus || 'UNKNOWN' },
233
+ statusMessage: { S: messageStatusDescription || '' },
234
+ countryCode: { S: isoCountryCode || '' },
235
+ carrier: { S: \`\${mcc || ''}-\${mnc || ''}\` },
236
+ priceInMillicents: { N: String(priceInMillicentsUSD || 0) },
237
+ timestamp: { S: now },
238
+ ttl: { N: String(Math.floor(Date.now() / 1000) + 30 * 24 * 60 * 60) },
239
+ },
240
+ }));
241
+
242
+ console.log(\`Tracked delivery for \${messageId}: \${messageStatus}\`);
243
+ } catch (error) {
244
+ console.error('Error tracking delivery:', error);
245
+ }
246
+ }
247
+
248
+ return { statusCode: 200 };
249
+ };
250
+ `
251
+
252
+ /**
253
+ * Create analytics DynamoDB table
254
+ */
255
+ static createAnalyticsTable(config: { slug: string }): Record<string, any> {
256
+ return {
257
+ [`${config.slug}SmsAnalyticsTable`]: {
258
+ Type: 'AWS::DynamoDB::Table',
259
+ Properties: {
260
+ TableName: `${config.slug}-sms-analytics`,
261
+ BillingMode: 'PAY_PER_REQUEST',
262
+ AttributeDefinitions: [
263
+ { AttributeName: 'period', AttributeType: 'S' },
264
+ ],
265
+ KeySchema: [
266
+ { AttributeName: 'period', KeyType: 'HASH' },
267
+ ],
268
+ TimeToLiveSpecification: {
269
+ AttributeName: 'ttl',
270
+ Enabled: true,
271
+ },
272
+ },
273
+ },
274
+ }
275
+ }
276
+
277
+ /**
278
+ * Create delivery reports table
279
+ */
280
+ static createDeliveryReportsTable(config: { slug: string }): Record<string, any> {
281
+ return {
282
+ [`${config.slug}SmsDeliveryReportsTable`]: {
283
+ Type: 'AWS::DynamoDB::Table',
284
+ Properties: {
285
+ TableName: `${config.slug}-sms-delivery-reports`,
286
+ BillingMode: 'PAY_PER_REQUEST',
287
+ AttributeDefinitions: [
288
+ { AttributeName: 'messageId', AttributeType: 'S' },
289
+ ],
290
+ KeySchema: [
291
+ { AttributeName: 'messageId', KeyType: 'HASH' },
292
+ ],
293
+ TimeToLiveSpecification: {
294
+ AttributeName: 'ttl',
295
+ Enabled: true,
296
+ },
297
+ },
298
+ },
299
+ }
300
+ }
301
+
302
+ /**
303
+ * Create analytics aggregator Lambda
304
+ */
305
+ static createAnalyticsAggregatorLambda(config: {
306
+ slug: string
307
+ roleArn: string
308
+ messageLogTable: string
309
+ analyticsTable: string
310
+ }): Record<string, any> {
311
+ return {
312
+ [`${config.slug}SmsAnalyticsAggregatorLambda`]: {
313
+ Type: 'AWS::Lambda::Function',
314
+ Properties: {
315
+ FunctionName: `${config.slug}-sms-analytics-aggregator`,
316
+ Runtime: 'nodejs20.x',
317
+ Handler: 'index.handler',
318
+ Role: config.roleArn,
319
+ Timeout: 60,
320
+ MemorySize: 256,
321
+ Code: {
322
+ ZipFile: SmsAnalytics.AnalyticsAggregatorCode,
323
+ },
324
+ Environment: {
325
+ Variables: {
326
+ MESSAGE_LOG_TABLE: config.messageLogTable,
327
+ ANALYTICS_TABLE: config.analyticsTable,
328
+ },
329
+ },
330
+ },
331
+ },
332
+ }
333
+ }
334
+ }
335
+
336
+ export default SmsAnalytics