@stacksjs/ts-cloud-core 0.1.7 → 0.1.9
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.
- package/package.json +7 -6
- package/src/advanced-features.test.ts +465 -0
- package/src/aws/cloudformation.ts +421 -0
- package/src/aws/cloudfront.ts +158 -0
- package/src/aws/credentials.test.ts +132 -0
- package/src/aws/credentials.ts +545 -0
- package/src/aws/index.ts +87 -0
- package/src/aws/s3.test.ts +188 -0
- package/src/aws/s3.ts +1088 -0
- package/src/aws/signature.test.ts +670 -0
- package/src/aws/signature.ts +1155 -0
- package/src/backup/disaster-recovery.test.ts +726 -0
- package/src/backup/disaster-recovery.ts +500 -0
- package/src/backup/index.ts +34 -0
- package/src/backup/manager.test.ts +498 -0
- package/src/backup/manager.ts +432 -0
- package/src/cicd/circleci.ts +430 -0
- package/src/cicd/github-actions.ts +424 -0
- package/src/cicd/gitlab-ci.ts +255 -0
- package/src/cicd/index.ts +8 -0
- package/src/cli/history.ts +396 -0
- package/src/cli/index.ts +10 -0
- package/src/cli/progress.ts +458 -0
- package/src/cli/repl.ts +454 -0
- package/src/cli/suggestions.ts +327 -0
- package/src/cli/table.test.ts +319 -0
- package/src/cli/table.ts +332 -0
- package/src/cloudformation/builder.test.ts +327 -0
- package/src/cloudformation/builder.ts +378 -0
- package/src/cloudformation/builders/api-gateway.ts +449 -0
- package/src/cloudformation/builders/cache.ts +334 -0
- package/src/cloudformation/builders/cdn.ts +278 -0
- package/src/cloudformation/builders/compute.ts +485 -0
- package/src/cloudformation/builders/database.ts +392 -0
- package/src/cloudformation/builders/functions.ts +343 -0
- package/src/cloudformation/builders/messaging.ts +140 -0
- package/src/cloudformation/builders/monitoring.ts +300 -0
- package/src/cloudformation/builders/network.ts +264 -0
- package/src/cloudformation/builders/queue.ts +147 -0
- package/src/cloudformation/builders/security.ts +399 -0
- package/src/cloudformation/builders/storage.ts +285 -0
- package/src/cloudformation/index.ts +30 -0
- package/src/cloudformation/types.ts +173 -0
- package/src/compliance/aws-config.ts +543 -0
- package/src/compliance/cloudtrail.ts +376 -0
- package/src/compliance/compliance.test.ts +423 -0
- package/src/compliance/guardduty.ts +446 -0
- package/src/compliance/index.ts +66 -0
- package/src/compliance/security-hub.ts +456 -0
- package/src/containers/build-optimization.ts +416 -0
- package/src/containers/containers.test.ts +508 -0
- package/src/containers/image-scanning.ts +360 -0
- package/src/containers/index.ts +9 -0
- package/src/containers/registry.ts +293 -0
- package/src/containers/service-mesh.ts +520 -0
- package/src/database/database.test.ts +762 -0
- package/src/database/index.ts +9 -0
- package/src/database/migrations.ts +444 -0
- package/src/database/performance.ts +528 -0
- package/src/database/replicas.ts +534 -0
- package/src/database/users.ts +494 -0
- package/src/dependency-graph.ts +143 -0
- package/src/deployment/ab-testing.ts +582 -0
- package/src/deployment/blue-green.ts +452 -0
- package/src/deployment/canary.ts +500 -0
- package/src/deployment/deployment.test.ts +526 -0
- package/src/deployment/index.ts +61 -0
- package/src/deployment/progressive.ts +62 -0
- package/src/dns/dns.test.ts +641 -0
- package/src/dns/dnssec.ts +315 -0
- package/src/dns/index.ts +8 -0
- package/src/dns/resolver.ts +496 -0
- package/src/dns/routing.ts +593 -0
- package/src/email/advanced/analytics.ts +445 -0
- package/src/email/advanced/index.ts +11 -0
- package/src/email/advanced/rules.ts +465 -0
- package/src/email/advanced/scheduling.ts +352 -0
- package/src/email/advanced/search.ts +412 -0
- package/src/email/advanced/shared-mailboxes.ts +404 -0
- package/src/email/advanced/templates.ts +455 -0
- package/src/email/advanced/threading.ts +281 -0
- package/src/email/analytics.ts +467 -0
- package/src/email/bounce-handling.ts +425 -0
- package/src/email/email.test.ts +431 -0
- package/src/email/handlers/__tests__/inbound.test.ts +38 -0
- package/src/email/handlers/__tests__/outbound.test.ts +37 -0
- package/src/email/handlers/converter.ts +227 -0
- package/src/email/handlers/feedback.ts +228 -0
- package/src/email/handlers/inbound.ts +169 -0
- package/src/email/handlers/outbound.ts +178 -0
- package/src/email/index.ts +15 -0
- package/src/email/reputation.ts +303 -0
- package/src/email/templates.ts +352 -0
- package/src/errors/index.test.ts +434 -0
- package/src/errors/index.ts +416 -0
- package/src/health-checks/index.ts +40 -0
- package/src/index.ts +360 -0
- package/src/intrinsic-functions.ts +118 -0
- package/src/lambda/concurrency.ts +330 -0
- package/src/lambda/destinations.ts +345 -0
- package/src/lambda/dlq.ts +425 -0
- package/src/lambda/index.ts +11 -0
- package/src/lambda/lambda.test.ts +840 -0
- package/src/lambda/layers.ts +263 -0
- package/src/lambda/versions.ts +376 -0
- package/src/lambda/vpc.ts +399 -0
- package/src/local/config.ts +114 -0
- package/src/local/index.ts +6 -0
- package/src/local/mock-aws.ts +351 -0
- package/src/modules/ai.ts +340 -0
- package/src/modules/api.ts +478 -0
- package/src/modules/auth.ts +805 -0
- package/src/modules/cache.ts +417 -0
- package/src/modules/cdn.ts +1062 -0
- package/src/modules/communication.ts +1094 -0
- package/src/modules/compute.ts +3348 -0
- package/src/modules/database.ts +554 -0
- package/src/modules/deployment.ts +1079 -0
- package/src/modules/dns.ts +337 -0
- package/src/modules/email.ts +1538 -0
- package/src/modules/filesystem.ts +515 -0
- package/src/modules/index.ts +32 -0
- package/src/modules/messaging.ts +486 -0
- package/src/modules/monitoring.ts +2086 -0
- package/src/modules/network.ts +664 -0
- package/src/modules/parameter-store.ts +325 -0
- package/src/modules/permissions.ts +1081 -0
- package/src/modules/phone.ts +494 -0
- package/src/modules/queue.ts +1260 -0
- package/src/modules/redirects.ts +464 -0
- package/src/modules/registry.ts +699 -0
- package/src/modules/search.ts +401 -0
- package/src/modules/secrets.ts +416 -0
- package/src/modules/security.ts +731 -0
- package/src/modules/sms.ts +389 -0
- package/src/modules/storage.ts +1120 -0
- package/src/modules/workflow.ts +680 -0
- package/src/multi-account/config.ts +521 -0
- package/src/multi-account/index.ts +7 -0
- package/src/multi-account/manager.ts +427 -0
- package/src/multi-region/cross-region.ts +410 -0
- package/src/multi-region/index.ts +8 -0
- package/src/multi-region/manager.ts +483 -0
- package/src/multi-region/regions.ts +435 -0
- package/src/network-security/index.ts +48 -0
- package/src/observability/index.ts +9 -0
- package/src/observability/logs.ts +522 -0
- package/src/observability/metrics.ts +460 -0
- package/src/observability/observability.test.ts +782 -0
- package/src/observability/synthetics.ts +568 -0
- package/src/observability/xray.ts +358 -0
- package/src/phone/advanced/analytics.ts +349 -0
- package/src/phone/advanced/callbacks.ts +428 -0
- package/src/phone/advanced/index.ts +8 -0
- package/src/phone/advanced/ivr-builder.ts +504 -0
- package/src/phone/advanced/recording.ts +310 -0
- package/src/phone/handlers/__tests__/incoming-call.test.ts +40 -0
- package/src/phone/handlers/incoming-call.ts +117 -0
- package/src/phone/handlers/missed-call.ts +116 -0
- package/src/phone/handlers/voicemail.ts +179 -0
- package/src/phone/index.ts +9 -0
- package/src/presets/api-backend.ts +134 -0
- package/src/presets/data-pipeline.ts +204 -0
- package/src/presets/extend.test.ts +295 -0
- package/src/presets/extend.ts +297 -0
- package/src/presets/fullstack-app.ts +144 -0
- package/src/presets/index.ts +27 -0
- package/src/presets/jamstack.ts +135 -0
- package/src/presets/microservices.ts +167 -0
- package/src/presets/ml-api.ts +208 -0
- package/src/presets/nodejs-server.ts +104 -0
- package/src/presets/nodejs-serverless.ts +114 -0
- package/src/presets/realtime-app.ts +184 -0
- package/src/presets/static-site.ts +64 -0
- package/src/presets/traditional-web-app.ts +339 -0
- package/src/presets/wordpress.ts +138 -0
- package/src/preview/github.test.ts +249 -0
- package/src/preview/github.ts +297 -0
- package/src/preview/index.ts +37 -0
- package/src/preview/manager.test.ts +440 -0
- package/src/preview/manager.ts +326 -0
- package/src/preview/notifications.test.ts +582 -0
- package/src/preview/notifications.ts +341 -0
- package/src/queue/batch-processing.ts +402 -0
- package/src/queue/dlq-monitoring.ts +402 -0
- package/src/queue/fifo.ts +342 -0
- package/src/queue/index.ts +9 -0
- package/src/queue/management.ts +428 -0
- package/src/queue/queue.test.ts +429 -0
- package/src/resource-mgmt/index.ts +39 -0
- package/src/resource-naming.ts +62 -0
- package/src/s3/index.ts +523 -0
- package/src/schema/cloud-config.schema.json +554 -0
- package/src/schema/index.ts +68 -0
- package/src/security/certificate-manager.ts +492 -0
- package/src/security/index.ts +9 -0
- package/src/security/scanning.ts +545 -0
- package/src/security/secrets-manager.ts +476 -0
- package/src/security/secrets-rotation.ts +456 -0
- package/src/security/security.test.ts +738 -0
- package/src/sms/advanced/ab-testing.ts +389 -0
- package/src/sms/advanced/analytics.ts +336 -0
- package/src/sms/advanced/campaigns.ts +523 -0
- package/src/sms/advanced/chatbot.ts +224 -0
- package/src/sms/advanced/index.ts +10 -0
- package/src/sms/advanced/link-tracking.ts +248 -0
- package/src/sms/advanced/mms.ts +308 -0
- package/src/sms/handlers/__tests__/send.test.ts +40 -0
- package/src/sms/handlers/delivery-status.ts +133 -0
- package/src/sms/handlers/receive.ts +162 -0
- package/src/sms/handlers/send.ts +174 -0
- package/src/sms/index.ts +9 -0
- package/src/stack-diff.ts +389 -0
- package/src/static-site/index.ts +85 -0
- package/src/template-builder.ts +110 -0
- package/src/template-validator.ts +574 -0
- package/src/utils/cache.ts +291 -0
- package/src/utils/diff.ts +269 -0
- package/src/utils/hash.ts +227 -0
- package/src/utils/index.ts +8 -0
- package/src/utils/parallel.ts +294 -0
- package/src/validators/credentials.test.ts +274 -0
- package/src/validators/credentials.ts +233 -0
- package/src/validators/quotas.test.ts +434 -0
- package/src/validators/quotas.ts +217 -0
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Email Threading and Conversation View
|
|
3
|
+
*
|
|
4
|
+
* Groups emails into conversations based on subject and references
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export interface EmailThread {
|
|
8
|
+
threadId: string
|
|
9
|
+
subject: string
|
|
10
|
+
participants: string[]
|
|
11
|
+
messageCount: number
|
|
12
|
+
unreadCount: number
|
|
13
|
+
lastMessageDate: string
|
|
14
|
+
firstMessageDate: string
|
|
15
|
+
messages: ThreadMessage[]
|
|
16
|
+
labels?: string[]
|
|
17
|
+
isStarred?: boolean
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface ThreadMessage {
|
|
21
|
+
messageId: string
|
|
22
|
+
from: string
|
|
23
|
+
fromName?: string
|
|
24
|
+
to: string[]
|
|
25
|
+
cc?: string[]
|
|
26
|
+
date: string
|
|
27
|
+
bodyPreview: string
|
|
28
|
+
isRead: boolean
|
|
29
|
+
hasAttachments: boolean
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Email Threading Module
|
|
34
|
+
*/
|
|
35
|
+
export class EmailThreading {
|
|
36
|
+
/**
|
|
37
|
+
* Lambda code for threading emails
|
|
38
|
+
*/
|
|
39
|
+
static ThreadingLambdaCode = `
|
|
40
|
+
const { S3Client, GetObjectCommand, PutObjectCommand, ListObjectsV2Command } = require('@aws-sdk/client-s3');
|
|
41
|
+
const crypto = require('crypto');
|
|
42
|
+
|
|
43
|
+
const s3 = new S3Client({});
|
|
44
|
+
const EMAIL_BUCKET = process.env.EMAIL_BUCKET;
|
|
45
|
+
|
|
46
|
+
exports.handler = async (event) => {
|
|
47
|
+
console.log('Email threading event:', JSON.stringify(event, null, 2));
|
|
48
|
+
|
|
49
|
+
for (const record of event.Records) {
|
|
50
|
+
try {
|
|
51
|
+
const bucket = record.s3?.bucket?.name || EMAIL_BUCKET;
|
|
52
|
+
const key = decodeURIComponent(record.s3?.object?.key?.replace(/\\+/g, ' ') || '');
|
|
53
|
+
|
|
54
|
+
if (!key.endsWith('/metadata.json')) continue;
|
|
55
|
+
|
|
56
|
+
// Get email metadata
|
|
57
|
+
const result = await s3.send(new GetObjectCommand({ Bucket: bucket, Key: key }));
|
|
58
|
+
const metadata = JSON.parse(await result.Body.transformToString());
|
|
59
|
+
|
|
60
|
+
// Extract mailbox path
|
|
61
|
+
const pathParts = key.split('/');
|
|
62
|
+
const domain = pathParts[1];
|
|
63
|
+
const localPart = pathParts[2];
|
|
64
|
+
const mailboxPath = \`mailboxes/\${domain}/\${localPart}\`;
|
|
65
|
+
|
|
66
|
+
// Generate thread ID from subject
|
|
67
|
+
const threadId = generateThreadId(metadata.subject, metadata.from, metadata.to);
|
|
68
|
+
|
|
69
|
+
// Update email metadata with thread ID
|
|
70
|
+
metadata.threadId = threadId;
|
|
71
|
+
await s3.send(new PutObjectCommand({
|
|
72
|
+
Bucket: bucket,
|
|
73
|
+
Key: key,
|
|
74
|
+
Body: JSON.stringify(metadata, null, 2),
|
|
75
|
+
ContentType: 'application/json',
|
|
76
|
+
}));
|
|
77
|
+
|
|
78
|
+
// Update thread index
|
|
79
|
+
await updateThreadIndex(bucket, mailboxPath, threadId, metadata);
|
|
80
|
+
|
|
81
|
+
console.log(\`Threaded email \${metadata.messageId} into thread \${threadId}\`);
|
|
82
|
+
} catch (error) {
|
|
83
|
+
console.error('Error threading email:', error);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return { statusCode: 200 };
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
function generateThreadId(subject, from, to) {
|
|
91
|
+
// Normalize subject (remove Re:, Fwd:, etc.)
|
|
92
|
+
const normalizedSubject = subject
|
|
93
|
+
.replace(/^(Re|Fwd|Fw|RE|FWD|FW):\\s*/gi, '')
|
|
94
|
+
.trim()
|
|
95
|
+
.toLowerCase();
|
|
96
|
+
|
|
97
|
+
// Create hash from normalized subject
|
|
98
|
+
const hash = crypto.createHash('md5')
|
|
99
|
+
.update(normalizedSubject)
|
|
100
|
+
.digest('hex')
|
|
101
|
+
.substring(0, 12);
|
|
102
|
+
|
|
103
|
+
return \`thread-\${hash}\`;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async function updateThreadIndex(bucket, mailboxPath, threadId, metadata) {
|
|
107
|
+
const threadsKey = \`\${mailboxPath}/threads.json\`;
|
|
108
|
+
let threads = {};
|
|
109
|
+
|
|
110
|
+
// Load existing threads
|
|
111
|
+
try {
|
|
112
|
+
const result = await s3.send(new GetObjectCommand({
|
|
113
|
+
Bucket: bucket,
|
|
114
|
+
Key: threadsKey,
|
|
115
|
+
}));
|
|
116
|
+
threads = JSON.parse(await result.Body.transformToString());
|
|
117
|
+
} catch {
|
|
118
|
+
// No threads file yet
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Get or create thread
|
|
122
|
+
if (!threads[threadId]) {
|
|
123
|
+
threads[threadId] = {
|
|
124
|
+
threadId,
|
|
125
|
+
subject: metadata.subject.replace(/^(Re|Fwd|Fw|RE|FWD|FW):\\s*/gi, '').trim(),
|
|
126
|
+
participants: [],
|
|
127
|
+
messageCount: 0,
|
|
128
|
+
unreadCount: 0,
|
|
129
|
+
messages: [],
|
|
130
|
+
firstMessageDate: metadata.date,
|
|
131
|
+
lastMessageDate: metadata.date,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const thread = threads[threadId];
|
|
136
|
+
|
|
137
|
+
// Add participant if not already in list
|
|
138
|
+
if (!thread.participants.includes(metadata.from)) {
|
|
139
|
+
thread.participants.push(metadata.from);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Add message to thread
|
|
143
|
+
thread.messages.push({
|
|
144
|
+
messageId: metadata.messageId,
|
|
145
|
+
from: metadata.from,
|
|
146
|
+
fromName: metadata.fromName,
|
|
147
|
+
to: [metadata.to],
|
|
148
|
+
date: metadata.date,
|
|
149
|
+
bodyPreview: metadata.preview || '',
|
|
150
|
+
isRead: false,
|
|
151
|
+
hasAttachments: metadata.hasAttachments || false,
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// Update counts
|
|
155
|
+
thread.messageCount = thread.messages.length;
|
|
156
|
+
thread.unreadCount = thread.messages.filter(m => !m.isRead).length;
|
|
157
|
+
|
|
158
|
+
// Update dates
|
|
159
|
+
if (new Date(metadata.date) > new Date(thread.lastMessageDate)) {
|
|
160
|
+
thread.lastMessageDate = metadata.date;
|
|
161
|
+
}
|
|
162
|
+
if (new Date(metadata.date) < new Date(thread.firstMessageDate)) {
|
|
163
|
+
thread.firstMessageDate = metadata.date;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Sort messages by date
|
|
167
|
+
thread.messages.sort((a, b) => new Date(a.date) - new Date(b.date));
|
|
168
|
+
|
|
169
|
+
// Save threads
|
|
170
|
+
await s3.send(new PutObjectCommand({
|
|
171
|
+
Bucket: bucket,
|
|
172
|
+
Key: threadsKey,
|
|
173
|
+
Body: JSON.stringify(threads, null, 2),
|
|
174
|
+
ContentType: 'application/json',
|
|
175
|
+
}));
|
|
176
|
+
}
|
|
177
|
+
`
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Create threading Lambda function
|
|
181
|
+
*/
|
|
182
|
+
static createThreadingLambda(config: {
|
|
183
|
+
slug: string
|
|
184
|
+
roleArn: string
|
|
185
|
+
emailBucket: string
|
|
186
|
+
}): Record<string, any> {
|
|
187
|
+
return {
|
|
188
|
+
[`${config.slug}EmailThreadingLambda`]: {
|
|
189
|
+
Type: 'AWS::Lambda::Function',
|
|
190
|
+
Properties: {
|
|
191
|
+
FunctionName: `${config.slug}-email-threading`,
|
|
192
|
+
Runtime: 'nodejs20.x',
|
|
193
|
+
Handler: 'index.handler',
|
|
194
|
+
Role: config.roleArn,
|
|
195
|
+
Timeout: 60,
|
|
196
|
+
MemorySize: 256,
|
|
197
|
+
Code: {
|
|
198
|
+
ZipFile: EmailThreading.ThreadingLambdaCode,
|
|
199
|
+
},
|
|
200
|
+
Environment: {
|
|
201
|
+
Variables: {
|
|
202
|
+
EMAIL_BUCKET: config.emailBucket,
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Get threads for a mailbox (SDK helper)
|
|
212
|
+
*/
|
|
213
|
+
static async getThreads(params: {
|
|
214
|
+
s3Client: any
|
|
215
|
+
bucket: string
|
|
216
|
+
mailbox: string
|
|
217
|
+
limit?: number
|
|
218
|
+
offset?: number
|
|
219
|
+
}): Promise<EmailThread[]> {
|
|
220
|
+
const { s3Client, bucket, mailbox, limit = 50, offset = 0 } = params
|
|
221
|
+
|
|
222
|
+
const [localPart, domain] = mailbox.includes('@')
|
|
223
|
+
? mailbox.split('@')
|
|
224
|
+
: [mailbox, 'default']
|
|
225
|
+
|
|
226
|
+
const threadsKey = `mailboxes/${domain}/${localPart}/threads.json`
|
|
227
|
+
|
|
228
|
+
try {
|
|
229
|
+
const result = await s3Client.send({
|
|
230
|
+
Bucket: bucket,
|
|
231
|
+
Key: threadsKey,
|
|
232
|
+
})
|
|
233
|
+
|
|
234
|
+
const threads = JSON.parse(result.Body)
|
|
235
|
+
const threadList = Object.values(threads) as EmailThread[]
|
|
236
|
+
|
|
237
|
+
// Sort by last message date
|
|
238
|
+
threadList.sort((a, b) =>
|
|
239
|
+
new Date(b.lastMessageDate).getTime() - new Date(a.lastMessageDate).getTime()
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
return threadList.slice(offset, offset + limit)
|
|
243
|
+
}
|
|
244
|
+
catch {
|
|
245
|
+
return []
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Get a specific thread
|
|
251
|
+
*/
|
|
252
|
+
static async getThread(params: {
|
|
253
|
+
s3Client: any
|
|
254
|
+
bucket: string
|
|
255
|
+
mailbox: string
|
|
256
|
+
threadId: string
|
|
257
|
+
}): Promise<EmailThread | null> {
|
|
258
|
+
const { s3Client, bucket, mailbox, threadId } = params
|
|
259
|
+
|
|
260
|
+
const [localPart, domain] = mailbox.includes('@')
|
|
261
|
+
? mailbox.split('@')
|
|
262
|
+
: [mailbox, 'default']
|
|
263
|
+
|
|
264
|
+
const threadsKey = `mailboxes/${domain}/${localPart}/threads.json`
|
|
265
|
+
|
|
266
|
+
try {
|
|
267
|
+
const result = await s3Client.send({
|
|
268
|
+
Bucket: bucket,
|
|
269
|
+
Key: threadsKey,
|
|
270
|
+
})
|
|
271
|
+
|
|
272
|
+
const threads = JSON.parse(result.Body)
|
|
273
|
+
return threads[threadId] || null
|
|
274
|
+
}
|
|
275
|
+
catch {
|
|
276
|
+
return null
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
export default EmailThreading
|