catalist-support-agent 1.0.0

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 (140) hide show
  1. package/dist/admin-portal.d.ts +43 -0
  2. package/dist/admin-portal.d.ts.map +1 -0
  3. package/dist/admin-portal.js +166 -0
  4. package/dist/admin-portal.js.map +1 -0
  5. package/dist/analysis/entities.d.ts +73 -0
  6. package/dist/analysis/entities.d.ts.map +1 -0
  7. package/dist/analysis/entities.js +378 -0
  8. package/dist/analysis/entities.js.map +1 -0
  9. package/dist/analysis/index.d.ts +44 -0
  10. package/dist/analysis/index.d.ts.map +1 -0
  11. package/dist/analysis/index.js +243 -0
  12. package/dist/analysis/index.js.map +1 -0
  13. package/dist/analysis/intent.d.ts +49 -0
  14. package/dist/analysis/intent.d.ts.map +1 -0
  15. package/dist/analysis/intent.js +320 -0
  16. package/dist/analysis/intent.js.map +1 -0
  17. package/dist/analysis/sentiment.d.ts +57 -0
  18. package/dist/analysis/sentiment.d.ts.map +1 -0
  19. package/dist/analysis/sentiment.js +351 -0
  20. package/dist/analysis/sentiment.js.map +1 -0
  21. package/dist/brand/compliance.d.ts +122 -0
  22. package/dist/brand/compliance.d.ts.map +1 -0
  23. package/dist/brand/compliance.js +378 -0
  24. package/dist/brand/compliance.js.map +1 -0
  25. package/dist/brand/forbidden-terms.d.ts +99 -0
  26. package/dist/brand/forbidden-terms.d.ts.map +1 -0
  27. package/dist/brand/forbidden-terms.js +265 -0
  28. package/dist/brand/forbidden-terms.js.map +1 -0
  29. package/dist/brand/index.d.ts +10 -0
  30. package/dist/brand/index.d.ts.map +1 -0
  31. package/dist/brand/index.js +12 -0
  32. package/dist/brand/index.js.map +1 -0
  33. package/dist/config.d.ts +325 -0
  34. package/dist/config.d.ts.map +1 -0
  35. package/dist/config.js +492 -0
  36. package/dist/config.js.map +1 -0
  37. package/dist/delivery/index.d.ts +84 -0
  38. package/dist/delivery/index.d.ts.map +1 -0
  39. package/dist/delivery/index.js +435 -0
  40. package/dist/delivery/index.js.map +1 -0
  41. package/dist/embeddings/cache.d.ts +96 -0
  42. package/dist/embeddings/cache.d.ts.map +1 -0
  43. package/dist/embeddings/cache.js +193 -0
  44. package/dist/embeddings/cache.js.map +1 -0
  45. package/dist/embeddings/index.d.ts +152 -0
  46. package/dist/embeddings/index.d.ts.map +1 -0
  47. package/dist/embeddings/index.js +337 -0
  48. package/dist/embeddings/index.js.map +1 -0
  49. package/dist/embeddings/openai-client.d.ts +67 -0
  50. package/dist/embeddings/openai-client.d.ts.map +1 -0
  51. package/dist/embeddings/openai-client.js +190 -0
  52. package/dist/embeddings/openai-client.js.map +1 -0
  53. package/dist/errors.d.ts +302 -0
  54. package/dist/errors.d.ts.map +1 -0
  55. package/dist/errors.js +508 -0
  56. package/dist/errors.js.map +1 -0
  57. package/dist/escalation/index.d.ts +93 -0
  58. package/dist/escalation/index.d.ts.map +1 -0
  59. package/dist/escalation/index.js +436 -0
  60. package/dist/escalation/index.js.map +1 -0
  61. package/dist/extraction/deduplication.d.ts +97 -0
  62. package/dist/extraction/deduplication.d.ts.map +1 -0
  63. package/dist/extraction/deduplication.js +271 -0
  64. package/dist/extraction/deduplication.js.map +1 -0
  65. package/dist/extraction/gmail-extractor.d.ts +160 -0
  66. package/dist/extraction/gmail-extractor.d.ts.map +1 -0
  67. package/dist/extraction/gmail-extractor.js +396 -0
  68. package/dist/extraction/gmail-extractor.js.map +1 -0
  69. package/dist/extraction/gmail-token-manager.d.ts +36 -0
  70. package/dist/extraction/gmail-token-manager.d.ts.map +1 -0
  71. package/dist/extraction/gmail-token-manager.js +146 -0
  72. package/dist/extraction/gmail-token-manager.js.map +1 -0
  73. package/dist/extraction/index.d.ts +13 -0
  74. package/dist/extraction/index.d.ts.map +1 -0
  75. package/dist/extraction/index.js +20 -0
  76. package/dist/extraction/index.js.map +1 -0
  77. package/dist/extraction/pii-handler.d.ts +100 -0
  78. package/dist/extraction/pii-handler.d.ts.map +1 -0
  79. package/dist/extraction/pii-handler.js +295 -0
  80. package/dist/extraction/pii-handler.js.map +1 -0
  81. package/dist/extraction/pipeline.d.ts +94 -0
  82. package/dist/extraction/pipeline.d.ts.map +1 -0
  83. package/dist/extraction/pipeline.js +380 -0
  84. package/dist/extraction/pipeline.js.map +1 -0
  85. package/dist/extraction/quality-filter.d.ts +99 -0
  86. package/dist/extraction/quality-filter.d.ts.map +1 -0
  87. package/dist/extraction/quality-filter.js +370 -0
  88. package/dist/extraction/quality-filter.js.map +1 -0
  89. package/dist/extraction/rate-limiter.d.ts +90 -0
  90. package/dist/extraction/rate-limiter.d.ts.map +1 -0
  91. package/dist/extraction/rate-limiter.js +242 -0
  92. package/dist/extraction/rate-limiter.js.map +1 -0
  93. package/dist/extraction/state-manager.d.ts +126 -0
  94. package/dist/extraction/state-manager.d.ts.map +1 -0
  95. package/dist/extraction/state-manager.js +344 -0
  96. package/dist/extraction/state-manager.js.map +1 -0
  97. package/dist/generation/index.d.ts +75 -0
  98. package/dist/generation/index.d.ts.map +1 -0
  99. package/dist/generation/index.js +641 -0
  100. package/dist/generation/index.js.map +1 -0
  101. package/dist/index.d.ts +96 -0
  102. package/dist/index.d.ts.map +1 -0
  103. package/dist/index.js +233 -0
  104. package/dist/index.js.map +1 -0
  105. package/dist/intake/index.d.ts +15 -0
  106. package/dist/intake/index.d.ts.map +1 -0
  107. package/dist/intake/index.js +19 -0
  108. package/dist/intake/index.js.map +1 -0
  109. package/dist/intake/normalizer.d.ts +163 -0
  110. package/dist/intake/normalizer.d.ts.map +1 -0
  111. package/dist/intake/normalizer.js +309 -0
  112. package/dist/intake/normalizer.js.map +1 -0
  113. package/dist/intake/postmark.d.ts +72 -0
  114. package/dist/intake/postmark.d.ts.map +1 -0
  115. package/dist/intake/postmark.js +276 -0
  116. package/dist/intake/postmark.js.map +1 -0
  117. package/dist/intake/slack.d.ts +106 -0
  118. package/dist/intake/slack.d.ts.map +1 -0
  119. package/dist/intake/slack.js +378 -0
  120. package/dist/intake/slack.js.map +1 -0
  121. package/dist/intake/twilio.d.ts +86 -0
  122. package/dist/intake/twilio.d.ts.map +1 -0
  123. package/dist/intake/twilio.js +283 -0
  124. package/dist/intake/twilio.js.map +1 -0
  125. package/dist/knowledge/index.d.ts +100 -0
  126. package/dist/knowledge/index.d.ts.map +1 -0
  127. package/dist/knowledge/index.js +516 -0
  128. package/dist/knowledge/index.js.map +1 -0
  129. package/dist/knowledge/invoice-resolver.d.ts +62 -0
  130. package/dist/knowledge/invoice-resolver.d.ts.map +1 -0
  131. package/dist/knowledge/invoice-resolver.js +267 -0
  132. package/dist/knowledge/invoice-resolver.js.map +1 -0
  133. package/dist/types.d.ts +535 -0
  134. package/dist/types.d.ts.map +1 -0
  135. package/dist/types.js +48 -0
  136. package/dist/types.js.map +1 -0
  137. package/ga-service-account.json +13 -0
  138. package/gmail-knowledge-migration.sql +149 -0
  139. package/nul +1 -0
  140. package/package.json +55 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postmark.js","sourceRoot":"","sources":["../../src/intake/postmark.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Slack Event Handler
3
+ *
4
+ * Receives incoming Slack events via Events API, validates signatures,
5
+ * and normalizes message events into the standard message format.
6
+ */
7
+ import type { InboundMessage } from '../types.js';
8
+ import { type SlackMessageEvent, type SlackEventWrapper } from './normalizer.js';
9
+ export interface SlackProcessResult {
10
+ success: boolean;
11
+ message?: InboundMessage;
12
+ contentHash?: string;
13
+ hasForbiddenTerms: boolean;
14
+ detectedTerms: string[];
15
+ error?: string;
16
+ isChallenge?: boolean;
17
+ challengeResponse?: string;
18
+ }
19
+ export interface SlackUrlVerification {
20
+ type: 'url_verification';
21
+ challenge: string;
22
+ token: string;
23
+ }
24
+ /**
25
+ * Validate Slack webhook signature using HMAC-SHA256
26
+ *
27
+ * Slack signs webhooks using:
28
+ * - Signing secret
29
+ * - Timestamp (to prevent replay attacks)
30
+ * - Request body
31
+ */
32
+ export declare function validateSlackSignature(signature: string, timestamp: string, body: string, signingSecret: string): boolean;
33
+ /**
34
+ * Validate Slack webhook request
35
+ */
36
+ export declare function validateSlackWebhook(signature: string, timestamp: string, body: string): boolean;
37
+ /**
38
+ * Check if event is URL verification challenge
39
+ */
40
+ export declare function isUrlVerification(event: unknown): event is SlackUrlVerification;
41
+ /**
42
+ * Check if event is a valid message event
43
+ */
44
+ export declare function isMessageEvent(event: SlackEventWrapper): boolean;
45
+ /**
46
+ * Check if message is a direct message (DM)
47
+ */
48
+ export declare function isDirectMessage(event: SlackMessageEvent): boolean;
49
+ /**
50
+ * Check if message is from a bot
51
+ */
52
+ export declare function isBotMessage(event: SlackMessageEvent): boolean;
53
+ /**
54
+ * Process a Slack message event
55
+ */
56
+ export declare function processSlackMessage(eventWrapper: SlackEventWrapper): Promise<SlackProcessResult>;
57
+ /**
58
+ * Full webhook handler for Slack events
59
+ */
60
+ export declare function handleSlackEvent(rawBody: string, signature: string, timestamp: string): Promise<SlackProcessResult>;
61
+ /**
62
+ * Parse Slack message text to extract mentions
63
+ */
64
+ export declare function extractMentions(text: string): string[];
65
+ /**
66
+ * Parse Slack message text to extract channel references
67
+ */
68
+ export declare function extractChannelReferences(text: string): string[];
69
+ /**
70
+ * Parse Slack message text to extract links
71
+ */
72
+ export declare function extractLinks(text: string): Array<{
73
+ url: string;
74
+ label?: string;
75
+ }>;
76
+ /**
77
+ * Clean Slack message text (remove formatting, expand entities)
78
+ */
79
+ export declare function cleanSlackText(text: string): string;
80
+ /**
81
+ * Determine if this is a B2B customer DM channel
82
+ * In practice, this would check against known customer Slack workspaces
83
+ */
84
+ export declare function isB2BCustomerChannel(teamId: string, channelId: string): {
85
+ isB2B: boolean;
86
+ reason?: string;
87
+ };
88
+ /**
89
+ * Check if message should be processed (not from internal team, etc.)
90
+ */
91
+ export declare function shouldProcessSlackMessage(eventWrapper: SlackEventWrapper): {
92
+ shouldProcess: boolean;
93
+ reason?: string;
94
+ };
95
+ /**
96
+ * Format text for Slack (basic markdown to Slack mrkdwn)
97
+ */
98
+ export declare function formatForSlack(text: string): string;
99
+ /**
100
+ * Generate Slack Block Kit message structure
101
+ */
102
+ export declare function generateSlackBlocks(text: string, options?: {
103
+ includeActions?: boolean;
104
+ conversationId?: string;
105
+ }): unknown[];
106
+ //# sourceMappingURL=slack.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slack.d.ts","sourceRoot":"","sources":["../../src/intake/slack.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,378 @@
1
+ /**
2
+ * Slack Event Handler
3
+ *
4
+ * Receives incoming Slack events via Events API, validates signatures,
5
+ * and normalizes message events into the standard message format.
6
+ */
7
+ import { createHmac, timingSafeEqual } from 'crypto';
8
+ import { config } from '../config.js';
9
+ import { IntakeError, WebhookValidationError } from '../errors.js';
10
+ import { normalizeSlackMessage, generateContentHash, validateMessageContent, scanAndAnnotateMessage, } from './normalizer.js';
11
+ // =============================================================================
12
+ // Signature Validation
13
+ // =============================================================================
14
+ /**
15
+ * Validate Slack webhook signature using HMAC-SHA256
16
+ *
17
+ * Slack signs webhooks using:
18
+ * - Signing secret
19
+ * - Timestamp (to prevent replay attacks)
20
+ * - Request body
21
+ */
22
+ export function validateSlackSignature(signature, timestamp, body, signingSecret) {
23
+ if (!signature || !timestamp || !signingSecret) {
24
+ return false;
25
+ }
26
+ // Check timestamp is recent (within 5 minutes)
27
+ const timestampSeconds = parseInt(timestamp, 10);
28
+ const now = Math.floor(Date.now() / 1000);
29
+ if (Math.abs(now - timestampSeconds) > 300) {
30
+ // Request is older than 5 minutes
31
+ return false;
32
+ }
33
+ // Build the signature base string
34
+ const sigBase = `v0:${timestamp}:${body}`;
35
+ // Generate expected signature
36
+ const expectedSignature = 'v0=' + createHmac('sha256', signingSecret).update(sigBase).digest('hex');
37
+ // Timing-safe comparison
38
+ try {
39
+ const sig1 = Buffer.from(signature);
40
+ const sig2 = Buffer.from(expectedSignature);
41
+ if (sig1.length !== sig2.length) {
42
+ return false;
43
+ }
44
+ return timingSafeEqual(sig1, sig2);
45
+ }
46
+ catch {
47
+ return false;
48
+ }
49
+ }
50
+ /**
51
+ * Validate Slack webhook request
52
+ */
53
+ export function validateSlackWebhook(signature, timestamp, body) {
54
+ const signingSecret = config.slack.signingSecret;
55
+ if (!signingSecret) {
56
+ // If no signing secret configured, skip signature validation
57
+ // This is not recommended for production
58
+ console.warn('Slack signing secret not configured - skipping signature validation');
59
+ return true;
60
+ }
61
+ return validateSlackSignature(signature, timestamp, body, signingSecret);
62
+ }
63
+ // =============================================================================
64
+ // Event Processing
65
+ // =============================================================================
66
+ /**
67
+ * Check if event is URL verification challenge
68
+ */
69
+ export function isUrlVerification(event) {
70
+ return (typeof event === 'object' &&
71
+ event !== null &&
72
+ 'type' in event &&
73
+ event.type === 'url_verification');
74
+ }
75
+ /**
76
+ * Check if event is a valid message event
77
+ */
78
+ export function isMessageEvent(event) {
79
+ return (event.type === 'event_callback' &&
80
+ event.event?.type === 'message' &&
81
+ !event.event.subtype && // Ignore edited messages, deleted messages, etc.
82
+ !!event.event.text &&
83
+ !!event.event.user);
84
+ }
85
+ /**
86
+ * Check if message is a direct message (DM)
87
+ */
88
+ export function isDirectMessage(event) {
89
+ return event.channel_type === 'im';
90
+ }
91
+ /**
92
+ * Check if message is from a bot
93
+ */
94
+ export function isBotMessage(event) {
95
+ // Messages from bots have a bot_id field or subtype of 'bot_message'
96
+ return event.subtype === 'bot_message' || ('bot_id' in event && !!event.bot_id);
97
+ }
98
+ /**
99
+ * Process a Slack message event
100
+ */
101
+ export async function processSlackMessage(eventWrapper) {
102
+ try {
103
+ const event = eventWrapper.event;
104
+ // Validate it's a processable message
105
+ if (!event.text?.trim()) {
106
+ return {
107
+ success: false,
108
+ hasForbiddenTerms: false,
109
+ detectedTerms: [],
110
+ error: 'Empty message',
111
+ };
112
+ }
113
+ // Skip bot messages
114
+ if (isBotMessage(event)) {
115
+ return {
116
+ success: false,
117
+ hasForbiddenTerms: false,
118
+ detectedTerms: [],
119
+ error: 'Bot message ignored',
120
+ };
121
+ }
122
+ // Normalize the message into standard format
123
+ const message = normalizeSlackMessage(event, eventWrapper.team_id);
124
+ // Validate content exists
125
+ validateMessageContent(message);
126
+ // Generate content hash for deduplication
127
+ const contentHash = generateContentHash(message);
128
+ // Scan for forbidden terms
129
+ const { hasForbiddenTerms, detectedTerms } = scanAndAnnotateMessage(message);
130
+ return {
131
+ success: true,
132
+ message,
133
+ contentHash,
134
+ hasForbiddenTerms,
135
+ detectedTerms,
136
+ };
137
+ }
138
+ catch (error) {
139
+ if (error instanceof IntakeError) {
140
+ return {
141
+ success: false,
142
+ hasForbiddenTerms: false,
143
+ detectedTerms: [],
144
+ error: error.message,
145
+ };
146
+ }
147
+ return {
148
+ success: false,
149
+ hasForbiddenTerms: false,
150
+ detectedTerms: [],
151
+ error: error instanceof Error ? error.message : 'Unknown error processing Slack message',
152
+ };
153
+ }
154
+ }
155
+ /**
156
+ * Full webhook handler for Slack events
157
+ */
158
+ export async function handleSlackEvent(rawBody, signature, timestamp) {
159
+ // Validate webhook signature
160
+ if (!validateSlackWebhook(signature, timestamp, rawBody)) {
161
+ throw new WebhookValidationError('slack', {
162
+ context: { reason: 'Invalid Slack signature' },
163
+ });
164
+ }
165
+ // Parse JSON body
166
+ let payload;
167
+ try {
168
+ payload = JSON.parse(rawBody);
169
+ }
170
+ catch {
171
+ return {
172
+ success: false,
173
+ hasForbiddenTerms: false,
174
+ detectedTerms: [],
175
+ error: 'Invalid JSON payload',
176
+ };
177
+ }
178
+ // Handle URL verification challenge
179
+ if (isUrlVerification(payload)) {
180
+ return {
181
+ success: true,
182
+ hasForbiddenTerms: false,
183
+ detectedTerms: [],
184
+ isChallenge: true,
185
+ challengeResponse: payload.challenge,
186
+ };
187
+ }
188
+ // Validate event structure
189
+ const eventWrapper = payload;
190
+ if (!isMessageEvent(eventWrapper)) {
191
+ return {
192
+ success: false,
193
+ hasForbiddenTerms: false,
194
+ detectedTerms: [],
195
+ error: 'Not a processable message event',
196
+ };
197
+ }
198
+ // Process the message
199
+ return processSlackMessage(eventWrapper);
200
+ }
201
+ // =============================================================================
202
+ // Slack Utilities
203
+ // =============================================================================
204
+ /**
205
+ * Parse Slack message text to extract mentions
206
+ */
207
+ export function extractMentions(text) {
208
+ // Slack mentions format: <@U12345678>
209
+ const mentionPattern = /<@([A-Z0-9]+)>/g;
210
+ const mentions = [];
211
+ let match;
212
+ while ((match = mentionPattern.exec(text)) !== null) {
213
+ if (match[1]) {
214
+ mentions.push(match[1]);
215
+ }
216
+ }
217
+ return mentions;
218
+ }
219
+ /**
220
+ * Parse Slack message text to extract channel references
221
+ */
222
+ export function extractChannelReferences(text) {
223
+ // Slack channel format: <#C12345678|channel-name>
224
+ const channelPattern = /<#([A-Z0-9]+)\|?[^>]*>/g;
225
+ const channels = [];
226
+ let match;
227
+ while ((match = channelPattern.exec(text)) !== null) {
228
+ if (match[1]) {
229
+ channels.push(match[1]);
230
+ }
231
+ }
232
+ return channels;
233
+ }
234
+ /**
235
+ * Parse Slack message text to extract links
236
+ */
237
+ export function extractLinks(text) {
238
+ // Slack link format: <https://example.com|Optional Label>
239
+ const linkPattern = /<(https?:\/\/[^|>]+)(?:\|([^>]+))?>/g;
240
+ const links = [];
241
+ let match;
242
+ while ((match = linkPattern.exec(text)) !== null) {
243
+ if (match[1]) {
244
+ links.push({
245
+ url: match[1],
246
+ label: match[2],
247
+ });
248
+ }
249
+ }
250
+ return links;
251
+ }
252
+ /**
253
+ * Clean Slack message text (remove formatting, expand entities)
254
+ */
255
+ export function cleanSlackText(text) {
256
+ return text
257
+ // Replace user mentions with @user
258
+ .replace(/<@([A-Z0-9]+)>/g, '@user')
259
+ // Replace channel mentions with #channel
260
+ .replace(/<#([A-Z0-9]+)\|([^>]+)>/g, '#$2')
261
+ .replace(/<#([A-Z0-9]+)>/g, '#channel')
262
+ // Replace links with just the URL or label
263
+ .replace(/<(https?:\/\/[^|>]+)\|([^>]+)>/g, '$2')
264
+ .replace(/<(https?:\/\/[^>]+)>/g, '$1')
265
+ // Replace special markup
266
+ .replace(/<!here>/g, '@here')
267
+ .replace(/<!channel>/g, '@channel')
268
+ .replace(/<!everyone>/g, '@everyone')
269
+ // Decode common entities
270
+ .replace(/&amp;/g, '&')
271
+ .replace(/&lt;/g, '<')
272
+ .replace(/&gt;/g, '>');
273
+ }
274
+ // =============================================================================
275
+ // Slack DM Context
276
+ // =============================================================================
277
+ /**
278
+ * Determine if this is a B2B customer DM channel
279
+ * In practice, this would check against known customer Slack workspaces
280
+ */
281
+ export function isB2BCustomerChannel(teamId, channelId) {
282
+ // This would typically check against a database of connected B2B accounts
283
+ // For now, we assume all DMs are from potential B2B customers
284
+ // Could add logic like:
285
+ // - Check if team_id is in our list of connected workspace
286
+ // - Check if the channel is a known customer support channel
287
+ // - etc.
288
+ return {
289
+ isB2B: true,
290
+ reason: 'Direct message channel',
291
+ };
292
+ }
293
+ /**
294
+ * Check if message should be processed (not from internal team, etc.)
295
+ */
296
+ export function shouldProcessSlackMessage(eventWrapper) {
297
+ const event = eventWrapper.event;
298
+ // Skip bot messages
299
+ if (isBotMessage(event)) {
300
+ return {
301
+ shouldProcess: false,
302
+ reason: 'Bot message',
303
+ };
304
+ }
305
+ // Skip messages without text
306
+ if (!event.text?.trim()) {
307
+ return {
308
+ shouldProcess: false,
309
+ reason: 'Empty message',
310
+ };
311
+ }
312
+ // Skip non-DM channels (we only handle B2B customer DMs)
313
+ if (event.channel_type && event.channel_type !== 'im') {
314
+ return {
315
+ shouldProcess: false,
316
+ reason: 'Not a direct message',
317
+ };
318
+ }
319
+ // Check if it's from a B2B customer
320
+ const b2bCheck = isB2BCustomerChannel(eventWrapper.team_id, event.channel);
321
+ if (!b2bCheck.isB2B) {
322
+ return {
323
+ shouldProcess: false,
324
+ reason: b2bCheck.reason || 'Not a B2B customer channel',
325
+ };
326
+ }
327
+ return {
328
+ shouldProcess: true,
329
+ };
330
+ }
331
+ // =============================================================================
332
+ // Response Formatting for Slack
333
+ // =============================================================================
334
+ /**
335
+ * Format text for Slack (basic markdown to Slack mrkdwn)
336
+ */
337
+ export function formatForSlack(text) {
338
+ return text
339
+ // Bold: **text** -> *text*
340
+ .replace(/\*\*([^*]+)\*\*/g, '*$1*')
341
+ // Italic: _text_ stays the same
342
+ // Code: `code` stays the same
343
+ // Links: [text](url) -> <url|text>
344
+ .replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<$2|$1>');
345
+ }
346
+ /**
347
+ * Generate Slack Block Kit message structure
348
+ */
349
+ export function generateSlackBlocks(text, options) {
350
+ const blocks = [
351
+ {
352
+ type: 'section',
353
+ text: {
354
+ type: 'mrkdwn',
355
+ text: formatForSlack(text),
356
+ },
357
+ },
358
+ ];
359
+ if (options?.includeActions && options.conversationId) {
360
+ blocks.push({
361
+ type: 'actions',
362
+ elements: [
363
+ {
364
+ type: 'button',
365
+ text: {
366
+ type: 'plain_text',
367
+ text: 'View in Portal',
368
+ emoji: true,
369
+ },
370
+ url: `${config.escalation.adminBaseUrl}/support/${options.conversationId}`,
371
+ action_id: 'view_in_portal',
372
+ },
373
+ ],
374
+ });
375
+ }
376
+ return blocks;
377
+ }
378
+ //# sourceMappingURL=slack.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slack.js","sourceRoot":"","sources":["../../src/intake/slack.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAEnE,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EACnB,sBAAsB,EACtB,sBAAsB,GAGvB,MAAM,iBAAiB,CAAC;AAuBzB,gFAAgF;AAChF,uBAAuB;AACvB,gFAAgF;AAEhF;;;;;;;GAOG;AACH,MAAM,UAAU,sBAAsB,CACpC,SAAiB,EACjB,SAAiB,EACjB,IAAY,EACZ,aAAqB;IAErB,IAAI,CAAC,SAAS,IAAI,CAAC,SAAS,IAAI,CAAC,aAAa,EAAE,CAAC;QAC/C,OAAO,KAAK,CAAC;IACf,CAAC;IAED,+CAA+C;IAC/C,MAAM,gBAAgB,GAAG,QAAQ,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IACjD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;IAE1C,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,gBAAgB,CAAC,GAAG,GAAG,EAAE,CAAC;QAC3C,kCAAkC;QAClC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,kCAAkC;IAClC,MAAM,OAAO,GAAG,MAAM,SAAS,IAAI,IAAI,EAAE,CAAC;IAE1C,8BAA8B;IAC9B,MAAM,iBAAiB,GAAG,KAAK,GAAG,UAAU,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAEpG,yBAAyB;IACzB,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACpC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QAE5C,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;YAChC,OAAO,KAAK,CAAC;QACf,CAAC;QAED,OAAO,eAAe,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAClC,SAAiB,EACjB,SAAiB,EACjB,IAAY;IAEZ,MAAM,aAAa,GAAG,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC;IAEjD,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,6DAA6D;QAC7D,yCAAyC;QACzC,OAAO,CAAC,IAAI,CAAC,qEAAqE,CAAC,CAAC;QACpF,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,sBAAsB,CAAC,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,aAAa,CAAC,CAAC;AAC3E,CAAC;AAED,gFAAgF;AAChF,mBAAmB;AACnB,gFAAgF;AAEhF;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAc;IAC9C,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,MAAM,IAAI,KAAK;QACd,KAA2B,CAAC,IAAI,KAAK,kBAAkB,CACzD,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,KAAwB;IACrD,OAAO,CACL,KAAK,CAAC,IAAI,KAAK,gBAAgB;QAC/B,KAAK,CAAC,KAAK,EAAE,IAAI,KAAK,SAAS;QAC/B,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,IAAI,iDAAiD;QACzE,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI;QAClB,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CACnB,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,KAAwB;IACtD,OAAO,KAAK,CAAC,YAAY,KAAK,IAAI,CAAC;AACrC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,KAAwB;IACnD,qEAAqE;IACrE,OAAO,KAAK,CAAC,OAAO,KAAK,aAAa,IAAI,CAAC,QAAQ,IAAI,KAAK,IAAI,CAAC,CAAE,KAA6B,CAAC,MAAM,CAAC,CAAC;AAC3G,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,YAA+B;IAE/B,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC;QAEjC,sCAAsC;QACtC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC;YACxB,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,iBAAiB,EAAE,KAAK;gBACxB,aAAa,EAAE,EAAE;gBACjB,KAAK,EAAE,eAAe;aACvB,CAAC;QACJ,CAAC;QAED,oBAAoB;QACpB,IAAI,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;YACxB,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,iBAAiB,EAAE,KAAK;gBACxB,aAAa,EAAE,EAAE;gBACjB,KAAK,EAAE,qBAAqB;aAC7B,CAAC;QACJ,CAAC;QAED,6CAA6C;QAC7C,MAAM,OAAO,GAAG,qBAAqB,CAAC,KAAK,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC;QAEnE,0BAA0B;QAC1B,sBAAsB,CAAC,OAAO,CAAC,CAAC;QAEhC,0CAA0C;QAC1C,MAAM,WAAW,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAC;QAEjD,2BAA2B;QAC3B,MAAM,EAAE,iBAAiB,EAAE,aAAa,EAAE,GAAG,sBAAsB,CAAC,OAAO,CAAC,CAAC;QAE7E,OAAO;YACL,OAAO,EAAE,IAAI;YACb,OAAO;YACP,WAAW;YACX,iBAAiB;YACjB,aAAa;SACd,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,WAAW,EAAE,CAAC;YACjC,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,iBAAiB,EAAE,KAAK;gBACxB,aAAa,EAAE,EAAE;gBACjB,KAAK,EAAE,KAAK,CAAC,OAAO;aACrB,CAAC;QACJ,CAAC;QAED,OAAO;YACL,OAAO,EAAE,KAAK;YACd,iBAAiB,EAAE,KAAK;YACxB,aAAa,EAAE,EAAE;YACjB,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,wCAAwC;SACzF,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,OAAe,EACf,SAAiB,EACjB,SAAiB;IAEjB,6BAA6B;IAC7B,IAAI,CAAC,oBAAoB,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,CAAC;QACzD,MAAM,IAAI,sBAAsB,CAAC,OAAO,EAAE;YACxC,OAAO,EAAE,EAAE,MAAM,EAAE,yBAAyB,EAAE;SAC/C,CAAC,CAAC;IACL,CAAC;IAED,kBAAkB;IAClB,IAAI,OAAgB,CAAC;IACrB,IAAI,CAAC;QACH,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;YACL,OAAO,EAAE,KAAK;YACd,iBAAiB,EAAE,KAAK;YACxB,aAAa,EAAE,EAAE;YACjB,KAAK,EAAE,sBAAsB;SAC9B,CAAC;IACJ,CAAC;IAED,oCAAoC;IACpC,IAAI,iBAAiB,CAAC,OAAO,CAAC,EAAE,CAAC;QAC/B,OAAO;YACL,OAAO,EAAE,IAAI;YACb,iBAAiB,EAAE,KAAK;YACxB,aAAa,EAAE,EAAE;YACjB,WAAW,EAAE,IAAI;YACjB,iBAAiB,EAAE,OAAO,CAAC,SAAS;SACrC,CAAC;IACJ,CAAC;IAED,2BAA2B;IAC3B,MAAM,YAAY,GAAG,OAA4B,CAAC;IAClD,IAAI,CAAC,cAAc,CAAC,YAAY,CAAC,EAAE,CAAC;QAClC,OAAO;YACL,OAAO,EAAE,KAAK;YACd,iBAAiB,EAAE,KAAK;YACxB,aAAa,EAAE,EAAE;YACjB,KAAK,EAAE,iCAAiC;SACzC,CAAC;IACJ,CAAC;IAED,sBAAsB;IACtB,OAAO,mBAAmB,CAAC,YAAY,CAAC,CAAC;AAC3C,CAAC;AAED,gFAAgF;AAChF,kBAAkB;AAClB,gFAAgF;AAEhF;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,sCAAsC;IACtC,MAAM,cAAc,GAAG,iBAAiB,CAAC;IACzC,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,IAAI,KAAK,CAAC;IAEV,OAAO,CAAC,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACpD,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;YACb,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,wBAAwB,CAAC,IAAY;IACnD,kDAAkD;IAClD,MAAM,cAAc,GAAG,yBAAyB,CAAC;IACjD,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,IAAI,KAAK,CAAC;IAEV,OAAO,CAAC,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACpD,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;YACb,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,0DAA0D;IAC1D,MAAM,WAAW,GAAG,sCAAsC,CAAC;IAC3D,MAAM,KAAK,GAA2C,EAAE,CAAC;IACzD,IAAI,KAAK,CAAC;IAEV,OAAO,CAAC,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACjD,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;YACb,KAAK,CAAC,IAAI,CAAC;gBACT,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC;gBACb,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;aAChB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,OAAO,IAAI;QACT,mCAAmC;SAClC,OAAO,CAAC,iBAAiB,EAAE,OAAO,CAAC;QACpC,yCAAyC;SACxC,OAAO,CAAC,0BAA0B,EAAE,KAAK,CAAC;SAC1C,OAAO,CAAC,iBAAiB,EAAE,UAAU,CAAC;QACvC,2CAA2C;SAC1C,OAAO,CAAC,iCAAiC,EAAE,IAAI,CAAC;SAChD,OAAO,CAAC,uBAAuB,EAAE,IAAI,CAAC;QACvC,yBAAyB;SACxB,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC;SAC5B,OAAO,CAAC,aAAa,EAAE,UAAU,CAAC;SAClC,OAAO,CAAC,cAAc,EAAE,WAAW,CAAC;QACrC,yBAAyB;SACxB,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC;SACtB,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC;SACrB,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;AAC3B,CAAC;AAED,gFAAgF;AAChF,mBAAmB;AACnB,gFAAgF;AAEhF;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,MAAc,EAAE,SAAiB;IAIpE,0EAA0E;IAC1E,8DAA8D;IAE9D,wBAAwB;IACxB,2DAA2D;IAC3D,6DAA6D;IAC7D,SAAS;IAET,OAAO;QACL,KAAK,EAAE,IAAI;QACX,MAAM,EAAE,wBAAwB;KACjC,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,yBAAyB,CAAC,YAA+B;IAIvE,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC;IAEjC,oBAAoB;IACpB,IAAI,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO;YACL,aAAa,EAAE,KAAK;YACpB,MAAM,EAAE,aAAa;SACtB,CAAC;IACJ,CAAC;IAED,6BAA6B;IAC7B,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC;QACxB,OAAO;YACL,aAAa,EAAE,KAAK;YACpB,MAAM,EAAE,eAAe;SACxB,CAAC;IACJ,CAAC;IAED,yDAAyD;IACzD,IAAI,KAAK,CAAC,YAAY,IAAI,KAAK,CAAC,YAAY,KAAK,IAAI,EAAE,CAAC;QACtD,OAAO;YACL,aAAa,EAAE,KAAK;YACpB,MAAM,EAAE,sBAAsB;SAC/B,CAAC;IACJ,CAAC;IAED,oCAAoC;IACpC,MAAM,QAAQ,GAAG,oBAAoB,CAAC,YAAY,CAAC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IAC3E,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QACpB,OAAO;YACL,aAAa,EAAE,KAAK;YACpB,MAAM,EAAE,QAAQ,CAAC,MAAM,IAAI,4BAA4B;SACxD,CAAC;IACJ,CAAC;IAED,OAAO;QACL,aAAa,EAAE,IAAI;KACpB,CAAC;AACJ,CAAC;AAED,gFAAgF;AAChF,gCAAgC;AAChC,gFAAgF;AAEhF;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,OAAO,IAAI;QACT,2BAA2B;SAC1B,OAAO,CAAC,kBAAkB,EAAE,MAAM,CAAC;QACpC,gCAAgC;QAChC,8BAA8B;QAC9B,mCAAmC;SAClC,OAAO,CAAC,0BAA0B,EAAE,SAAS,CAAC,CAAC;AACpD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CACjC,IAAY,EACZ,OAGC;IAED,MAAM,MAAM,GAAc;QACxB;YACE,IAAI,EAAE,SAAS;YACf,IAAI,EAAE;gBACJ,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,cAAc,CAAC,IAAI,CAAC;aAC3B;SACF;KACF,CAAC;IAEF,IAAI,OAAO,EAAE,cAAc,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;QACtD,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,SAAS;YACf,QAAQ,EAAE;gBACR;oBACE,IAAI,EAAE,QAAQ;oBACd,IAAI,EAAE;wBACJ,IAAI,EAAE,YAAY;wBAClB,IAAI,EAAE,gBAAgB;wBACtB,KAAK,EAAE,IAAI;qBACZ;oBACD,GAAG,EAAE,GAAG,MAAM,CAAC,UAAU,CAAC,YAAY,YAAY,OAAO,CAAC,cAAc,EAAE;oBAC1E,SAAS,EAAE,gBAAgB;iBAC5B;aACF;SACF,CAAC,CAAC;IACL,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Twilio SMS Webhook Handler
3
+ *
4
+ * Receives incoming SMS messages via Twilio webhook, validates signatures,
5
+ * and normalizes SMS content into the standard message format.
6
+ */
7
+ import type { InboundMessage } from '../types.js';
8
+ import { type TwilioInboundSms } from './normalizer.js';
9
+ export interface TwilioProcessResult {
10
+ success: boolean;
11
+ message?: InboundMessage;
12
+ contentHash?: string;
13
+ hasForbiddenTerms: boolean;
14
+ detectedTerms: string[];
15
+ error?: string;
16
+ }
17
+ /**
18
+ * Validate Twilio webhook signature using HMAC-SHA1
19
+ *
20
+ * Twilio signs webhooks using the auth token and the full URL + params
21
+ */
22
+ export declare function validateTwilioSignature(signature: string, url: string, params: Record<string, string>, authToken: string): boolean;
23
+ /**
24
+ * Validate Twilio webhook request
25
+ */
26
+ export declare function validateTwilioWebhook(signature: string, url: string, params: Record<string, string>): boolean;
27
+ /**
28
+ * Parse Twilio webhook body (URL-encoded)
29
+ */
30
+ export declare function parseTwilioBody(body: string): TwilioInboundSms;
31
+ /**
32
+ * Process an inbound Twilio SMS
33
+ */
34
+ export declare function processTwilioSms(payload: TwilioInboundSms): Promise<TwilioProcessResult>;
35
+ /**
36
+ * Full webhook handler for Twilio inbound SMS
37
+ */
38
+ export declare function handleTwilioInbound(rawBody: string, signature: string, webhookUrl: string): Promise<TwilioProcessResult>;
39
+ /**
40
+ * Check if message is a STOP/unsubscribe request
41
+ */
42
+ export declare function isOptOutMessage(body: string): boolean;
43
+ /**
44
+ * Check if message is a help request
45
+ */
46
+ export declare function isHelpRequest(body: string): boolean;
47
+ /**
48
+ * Classify SMS message type
49
+ */
50
+ export declare function classifySms(sms: TwilioInboundSms): {
51
+ shouldProcess: boolean;
52
+ reason?: string;
53
+ classification: 'support' | 'opt_out' | 'help' | 'empty';
54
+ };
55
+ /**
56
+ * Check if SMS includes media attachments (MMS)
57
+ */
58
+ export declare function hasMmsAttachments(sms: TwilioInboundSms): boolean;
59
+ /**
60
+ * Extract MMS media URLs
61
+ */
62
+ export declare function extractMmsMedia(sms: TwilioInboundSms): Array<{
63
+ url: string;
64
+ contentType: string;
65
+ }>;
66
+ /**
67
+ * Extract country code from phone number
68
+ */
69
+ export declare function extractCountryCode(phone: string): string | undefined;
70
+ /**
71
+ * Determine if phone number is US/Canada
72
+ */
73
+ export declare function isNorthAmericanNumber(phone: string): boolean;
74
+ /**
75
+ * Generate TwiML response for immediate reply
76
+ */
77
+ export declare function generateTwimlResponse(message?: string): string;
78
+ /**
79
+ * Generate TwiML for opt-out confirmation
80
+ */
81
+ export declare function generateOptOutResponse(): string;
82
+ /**
83
+ * Generate TwiML for help response
84
+ */
85
+ export declare function generateHelpResponse(): string;
86
+ //# sourceMappingURL=twilio.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"twilio.d.ts","sourceRoot":"","sources":["../../src/intake/twilio.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAML,KAAK,gBAAgB,EACtB,MAAM,iBAAiB,CAAC;AAMzB,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAMD;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,SAAS,EAAE,MAAM,GAChB,OAAO,CA6BT;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC7B,OAAO,CAST;AAMD;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,CAS9D;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,mBAAmB,CAAC,CAsC9B;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,mBAAmB,CAAC,CAqB9B;AAMD;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAerD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAKnD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,gBAAgB,GAAG;IAClD,aAAa,EAAE,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,SAAS,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;CAC1D,CA8BA;AAMD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAGhE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,gBAAgB,GACpB,KAAK,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC,CAiB7C;AAMD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAwBpE;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAG5D;AAMD;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAe9D;AAED;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,CAI/C;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAI7C"}