digital-workers 0.1.1 → 2.0.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.
- package/.turbo/turbo-build.log +5 -0
- package/CHANGELOG.md +9 -0
- package/README.md +290 -106
- package/dist/actions.d.ts +95 -0
- package/dist/actions.d.ts.map +1 -0
- package/dist/actions.js +437 -0
- package/dist/actions.js.map +1 -0
- package/dist/approve.d.ts +49 -0
- package/dist/approve.d.ts.map +1 -0
- package/dist/approve.js +235 -0
- package/dist/approve.js.map +1 -0
- package/dist/ask.d.ts +42 -0
- package/dist/ask.d.ts.map +1 -0
- package/dist/ask.js +227 -0
- package/dist/ask.js.map +1 -0
- package/dist/decide.d.ts +62 -0
- package/dist/decide.d.ts.map +1 -0
- package/dist/decide.js +245 -0
- package/dist/decide.js.map +1 -0
- package/dist/do.d.ts +63 -0
- package/dist/do.d.ts.map +1 -0
- package/dist/do.js +228 -0
- package/dist/do.js.map +1 -0
- package/dist/generate.d.ts +61 -0
- package/dist/generate.d.ts.map +1 -0
- package/dist/generate.js +299 -0
- package/dist/generate.js.map +1 -0
- package/dist/goals.d.ts +89 -0
- package/dist/goals.d.ts.map +1 -0
- package/dist/goals.js +206 -0
- package/dist/goals.js.map +1 -0
- package/dist/index.d.ts +68 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +69 -0
- package/dist/index.js.map +1 -0
- package/dist/is.d.ts +54 -0
- package/dist/is.d.ts.map +1 -0
- package/dist/is.js +318 -0
- package/dist/is.js.map +1 -0
- package/dist/kpis.d.ts +103 -0
- package/dist/kpis.d.ts.map +1 -0
- package/dist/kpis.js +271 -0
- package/dist/kpis.js.map +1 -0
- package/dist/notify.d.ts +47 -0
- package/dist/notify.d.ts.map +1 -0
- package/dist/notify.js +220 -0
- package/dist/notify.js.map +1 -0
- package/dist/role.d.ts +53 -0
- package/dist/role.d.ts.map +1 -0
- package/dist/role.js +111 -0
- package/dist/role.js.map +1 -0
- package/dist/team.d.ts +61 -0
- package/dist/team.d.ts.map +1 -0
- package/dist/team.js +131 -0
- package/dist/team.js.map +1 -0
- package/dist/transports.d.ts +164 -0
- package/dist/transports.d.ts.map +1 -0
- package/dist/transports.js +358 -0
- package/dist/transports.js.map +1 -0
- package/dist/types.d.ts +693 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +72 -0
- package/dist/types.js.map +1 -0
- package/package.json +27 -61
- package/src/actions.ts +615 -0
- package/src/approve.ts +317 -0
- package/src/ask.ts +304 -0
- package/src/decide.ts +295 -0
- package/src/do.ts +275 -0
- package/src/generate.ts +364 -0
- package/src/goals.ts +220 -0
- package/src/index.ts +118 -0
- package/src/is.ts +372 -0
- package/src/kpis.ts +348 -0
- package/src/notify.ts +303 -0
- package/src/role.ts +116 -0
- package/src/team.ts +142 -0
- package/src/transports.ts +504 -0
- package/src/types.ts +843 -0
- package/test/actions.test.ts +546 -0
- package/test/standalone.test.ts +299 -0
- package/test/types.test.ts +460 -0
- package/tsconfig.json +9 -0
|
@@ -0,0 +1,504 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Communication Transports Bridge
|
|
3
|
+
*
|
|
4
|
+
* Connects digital-workers contact channels to digital-tools
|
|
5
|
+
* communication providers (Message, Call).
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type {
|
|
11
|
+
Worker,
|
|
12
|
+
Team,
|
|
13
|
+
WorkerRef,
|
|
14
|
+
Contacts,
|
|
15
|
+
ContactChannel,
|
|
16
|
+
NotifyActionData,
|
|
17
|
+
AskActionData,
|
|
18
|
+
ApproveActionData,
|
|
19
|
+
NotifyResult,
|
|
20
|
+
AskResult,
|
|
21
|
+
ApprovalResult,
|
|
22
|
+
} from './types.js'
|
|
23
|
+
|
|
24
|
+
// =============================================================================
|
|
25
|
+
// Transport Types
|
|
26
|
+
// =============================================================================
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Communication transport - maps contact channels to delivery mechanisms
|
|
30
|
+
*/
|
|
31
|
+
export type Transport =
|
|
32
|
+
| 'email' // Email transport (SendGrid, Resend, etc.)
|
|
33
|
+
| 'sms' // SMS transport (Twilio, etc.)
|
|
34
|
+
| 'voice' // Voice call transport (Vapi, Twilio, etc.)
|
|
35
|
+
| 'slack' // Slack API
|
|
36
|
+
| 'teams' // Microsoft Teams API
|
|
37
|
+
| 'discord' // Discord API
|
|
38
|
+
| 'whatsapp' // WhatsApp Business API
|
|
39
|
+
| 'telegram' // Telegram Bot API
|
|
40
|
+
| 'web' // Web push/in-app
|
|
41
|
+
| 'webhook' // Generic webhook
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Transport configuration
|
|
45
|
+
*/
|
|
46
|
+
export interface TransportConfig {
|
|
47
|
+
transport: Transport
|
|
48
|
+
provider?: string // Specific provider (e.g., 'sendgrid', 'resend')
|
|
49
|
+
apiKey?: string
|
|
50
|
+
apiUrl?: string
|
|
51
|
+
options?: Record<string, unknown>
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Message payload for transport
|
|
56
|
+
*/
|
|
57
|
+
export interface MessagePayload {
|
|
58
|
+
// Addressing
|
|
59
|
+
to: string | string[]
|
|
60
|
+
from?: string
|
|
61
|
+
replyTo?: string
|
|
62
|
+
|
|
63
|
+
// Content
|
|
64
|
+
subject?: string
|
|
65
|
+
body: string
|
|
66
|
+
html?: string
|
|
67
|
+
|
|
68
|
+
// Metadata
|
|
69
|
+
type: 'notification' | 'question' | 'approval'
|
|
70
|
+
priority?: 'low' | 'normal' | 'high' | 'urgent'
|
|
71
|
+
threadId?: string
|
|
72
|
+
metadata?: Record<string, unknown>
|
|
73
|
+
|
|
74
|
+
// Interactive (for questions/approvals)
|
|
75
|
+
actions?: MessageAction[]
|
|
76
|
+
schema?: unknown // SimpleSchema from ai-functions
|
|
77
|
+
timeout?: number
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Interactive message action
|
|
82
|
+
*/
|
|
83
|
+
export interface MessageAction {
|
|
84
|
+
id: string
|
|
85
|
+
label: string
|
|
86
|
+
style?: 'primary' | 'secondary' | 'danger'
|
|
87
|
+
value?: unknown
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Transport delivery result
|
|
92
|
+
*/
|
|
93
|
+
export interface DeliveryResult {
|
|
94
|
+
success: boolean
|
|
95
|
+
transport: Transport
|
|
96
|
+
messageId?: string
|
|
97
|
+
error?: string
|
|
98
|
+
metadata?: Record<string, unknown>
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// =============================================================================
|
|
102
|
+
// Channel to Transport Mapping
|
|
103
|
+
// =============================================================================
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Map contact channel to transport
|
|
107
|
+
*/
|
|
108
|
+
export function channelToTransport(channel: ContactChannel): Transport {
|
|
109
|
+
const mapping: Record<ContactChannel, Transport> = {
|
|
110
|
+
email: 'email',
|
|
111
|
+
slack: 'slack',
|
|
112
|
+
teams: 'teams',
|
|
113
|
+
discord: 'discord',
|
|
114
|
+
phone: 'voice',
|
|
115
|
+
sms: 'sms',
|
|
116
|
+
whatsapp: 'whatsapp',
|
|
117
|
+
telegram: 'telegram',
|
|
118
|
+
web: 'web',
|
|
119
|
+
api: 'webhook',
|
|
120
|
+
webhook: 'webhook',
|
|
121
|
+
}
|
|
122
|
+
return mapping[channel] || 'webhook'
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Get available transports for a worker
|
|
127
|
+
*/
|
|
128
|
+
export function getWorkerTransports(worker: Worker): Transport[] {
|
|
129
|
+
const transports: Transport[] = []
|
|
130
|
+
const contacts = worker.contacts
|
|
131
|
+
|
|
132
|
+
if (contacts.email) transports.push('email')
|
|
133
|
+
if (contacts.slack) transports.push('slack')
|
|
134
|
+
if (contacts.teams) transports.push('teams')
|
|
135
|
+
if (contacts.discord) transports.push('discord')
|
|
136
|
+
if (contacts.phone) transports.push('voice')
|
|
137
|
+
if (contacts.sms) transports.push('sms')
|
|
138
|
+
if (contacts.whatsapp) transports.push('whatsapp')
|
|
139
|
+
if (contacts.telegram) transports.push('telegram')
|
|
140
|
+
if (contacts.web) transports.push('web')
|
|
141
|
+
if (contacts.webhook) transports.push('webhook')
|
|
142
|
+
|
|
143
|
+
return transports
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Get team transports (union of all member transports + team contacts)
|
|
148
|
+
*/
|
|
149
|
+
export function getTeamTransports(team: Team): Transport[] {
|
|
150
|
+
const transports = new Set<Transport>()
|
|
151
|
+
|
|
152
|
+
// Add team-level contacts
|
|
153
|
+
const contacts = team.contacts
|
|
154
|
+
if (contacts.email) transports.add('email')
|
|
155
|
+
if (contacts.slack) transports.add('slack')
|
|
156
|
+
if (contacts.teams) transports.add('teams')
|
|
157
|
+
if (contacts.discord) transports.add('discord')
|
|
158
|
+
if (contacts.phone) transports.add('voice')
|
|
159
|
+
if (contacts.sms) transports.add('sms')
|
|
160
|
+
if (contacts.whatsapp) transports.add('whatsapp')
|
|
161
|
+
if (contacts.telegram) transports.add('telegram')
|
|
162
|
+
if (contacts.web) transports.add('web')
|
|
163
|
+
if (contacts.webhook) transports.add('webhook')
|
|
164
|
+
|
|
165
|
+
return Array.from(transports)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// =============================================================================
|
|
169
|
+
// Address Resolution
|
|
170
|
+
// =============================================================================
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Identifier for a communication address
|
|
174
|
+
*/
|
|
175
|
+
export interface Address {
|
|
176
|
+
transport: Transport
|
|
177
|
+
value: string
|
|
178
|
+
name?: string
|
|
179
|
+
metadata?: Record<string, unknown>
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Resolve contact to address
|
|
184
|
+
*/
|
|
185
|
+
export function resolveAddress(contacts: Contacts, channel: ContactChannel): Address | null {
|
|
186
|
+
const contact = contacts[channel]
|
|
187
|
+
if (!contact) return null
|
|
188
|
+
|
|
189
|
+
const transport = channelToTransport(channel)
|
|
190
|
+
|
|
191
|
+
if (typeof contact === 'string') {
|
|
192
|
+
return { transport, value: contact }
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Handle structured contact types
|
|
196
|
+
switch (channel) {
|
|
197
|
+
case 'email':
|
|
198
|
+
const emailContact = contact as { address: string; name?: string }
|
|
199
|
+
return { transport, value: emailContact.address, name: emailContact.name }
|
|
200
|
+
case 'phone':
|
|
201
|
+
case 'sms':
|
|
202
|
+
case 'whatsapp':
|
|
203
|
+
const phoneContact = contact as { number: string }
|
|
204
|
+
return { transport, value: phoneContact.number }
|
|
205
|
+
case 'slack':
|
|
206
|
+
const slackContact = contact as { user?: string; channel?: string; workspace?: string }
|
|
207
|
+
return {
|
|
208
|
+
transport,
|
|
209
|
+
value: slackContact.user || slackContact.channel || '',
|
|
210
|
+
metadata: { workspace: slackContact.workspace },
|
|
211
|
+
}
|
|
212
|
+
case 'teams':
|
|
213
|
+
const teamsContact = contact as { user?: string; channel?: string; team?: string }
|
|
214
|
+
return {
|
|
215
|
+
transport,
|
|
216
|
+
value: teamsContact.user || teamsContact.channel || '',
|
|
217
|
+
metadata: { team: teamsContact.team },
|
|
218
|
+
}
|
|
219
|
+
case 'discord':
|
|
220
|
+
const discordContact = contact as { user?: string; channel?: string; server?: string }
|
|
221
|
+
return {
|
|
222
|
+
transport,
|
|
223
|
+
value: discordContact.user || discordContact.channel || '',
|
|
224
|
+
metadata: { server: discordContact.server },
|
|
225
|
+
}
|
|
226
|
+
case 'telegram':
|
|
227
|
+
const telegramContact = contact as { user?: string; chat?: string }
|
|
228
|
+
return { transport, value: telegramContact.user || telegramContact.chat || '' }
|
|
229
|
+
case 'web':
|
|
230
|
+
const webContact = contact as { userId?: string; url?: string }
|
|
231
|
+
return { transport, value: webContact.userId || '', metadata: { url: webContact.url } }
|
|
232
|
+
case 'webhook':
|
|
233
|
+
const webhookContact = contact as { url: string; secret?: string }
|
|
234
|
+
return { transport, value: webhookContact.url, metadata: { secret: webhookContact.secret } }
|
|
235
|
+
case 'api':
|
|
236
|
+
const apiContact = contact as { endpoint: string; auth?: string }
|
|
237
|
+
return { transport, value: apiContact.endpoint, metadata: { auth: apiContact.auth } }
|
|
238
|
+
default:
|
|
239
|
+
return null
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Resolve all addresses for a worker
|
|
245
|
+
*/
|
|
246
|
+
export function resolveWorkerAddresses(worker: Worker): Address[] {
|
|
247
|
+
const addresses: Address[] = []
|
|
248
|
+
const channels: ContactChannel[] = [
|
|
249
|
+
'email', 'slack', 'teams', 'discord', 'phone', 'sms',
|
|
250
|
+
'whatsapp', 'telegram', 'web', 'api', 'webhook',
|
|
251
|
+
]
|
|
252
|
+
|
|
253
|
+
for (const channel of channels) {
|
|
254
|
+
const address = resolveAddress(worker.contacts, channel)
|
|
255
|
+
if (address) addresses.push(address)
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return addresses
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Get primary address for a worker based on preferences
|
|
263
|
+
*/
|
|
264
|
+
export function getPrimaryAddress(worker: Worker): Address | null {
|
|
265
|
+
const preferences = worker.preferences
|
|
266
|
+
if (preferences?.primary) {
|
|
267
|
+
return resolveAddress(worker.contacts, preferences.primary)
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Default priority: slack > email > teams > sms > phone
|
|
271
|
+
const defaultPriority: ContactChannel[] = ['slack', 'email', 'teams', 'sms', 'phone']
|
|
272
|
+
for (const channel of defaultPriority) {
|
|
273
|
+
const address = resolveAddress(worker.contacts, channel)
|
|
274
|
+
if (address) return address
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Fall back to any available
|
|
278
|
+
const addresses = resolveWorkerAddresses(worker)
|
|
279
|
+
return addresses[0] || null
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// =============================================================================
|
|
283
|
+
// Transport Registry
|
|
284
|
+
// =============================================================================
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Transport handler function type
|
|
288
|
+
*/
|
|
289
|
+
export type TransportHandler = (
|
|
290
|
+
payload: MessagePayload,
|
|
291
|
+
config: TransportConfig
|
|
292
|
+
) => Promise<DeliveryResult>
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Transport registry
|
|
296
|
+
*/
|
|
297
|
+
const transportRegistry = new Map<Transport, TransportHandler>()
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Register a transport handler
|
|
301
|
+
*/
|
|
302
|
+
export function registerTransport(transport: Transport, handler: TransportHandler): void {
|
|
303
|
+
transportRegistry.set(transport, handler)
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Get transport handler
|
|
308
|
+
*/
|
|
309
|
+
export function getTransportHandler(transport: Transport): TransportHandler | undefined {
|
|
310
|
+
return transportRegistry.get(transport)
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Check if transport is registered
|
|
315
|
+
*/
|
|
316
|
+
export function hasTransport(transport: Transport): boolean {
|
|
317
|
+
return transportRegistry.has(transport)
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* List registered transports
|
|
322
|
+
*/
|
|
323
|
+
export function listTransports(): Transport[] {
|
|
324
|
+
return Array.from(transportRegistry.keys())
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// =============================================================================
|
|
328
|
+
// Default Transport Handlers (Stubs - implemented by providers)
|
|
329
|
+
// =============================================================================
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Send via transport
|
|
333
|
+
*/
|
|
334
|
+
export async function sendViaTransport(
|
|
335
|
+
transport: Transport,
|
|
336
|
+
payload: MessagePayload,
|
|
337
|
+
config?: TransportConfig
|
|
338
|
+
): Promise<DeliveryResult> {
|
|
339
|
+
const handler = transportRegistry.get(transport)
|
|
340
|
+
if (!handler) {
|
|
341
|
+
return {
|
|
342
|
+
success: false,
|
|
343
|
+
transport,
|
|
344
|
+
error: `Transport '${transport}' not registered`,
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
try {
|
|
349
|
+
return await handler(payload, config || { transport })
|
|
350
|
+
} catch (error) {
|
|
351
|
+
return {
|
|
352
|
+
success: false,
|
|
353
|
+
transport,
|
|
354
|
+
error: error instanceof Error ? error.message : String(error),
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Send to multiple transports (fan-out)
|
|
361
|
+
*/
|
|
362
|
+
export async function sendToMultipleTransports(
|
|
363
|
+
transports: Transport[],
|
|
364
|
+
payload: MessagePayload,
|
|
365
|
+
configs?: Record<Transport, TransportConfig>
|
|
366
|
+
): Promise<DeliveryResult[]> {
|
|
367
|
+
const results = await Promise.all(
|
|
368
|
+
transports.map(transport =>
|
|
369
|
+
sendViaTransport(transport, payload, configs?.[transport])
|
|
370
|
+
)
|
|
371
|
+
)
|
|
372
|
+
return results
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// =============================================================================
|
|
376
|
+
// Worker Action to Transport
|
|
377
|
+
// =============================================================================
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Build message payload from notify action
|
|
381
|
+
*/
|
|
382
|
+
export function buildNotifyPayload(action: NotifyActionData): MessagePayload {
|
|
383
|
+
return {
|
|
384
|
+
to: resolveActionTarget(action.object),
|
|
385
|
+
body: action.message,
|
|
386
|
+
type: 'notification',
|
|
387
|
+
priority: action.priority || 'normal',
|
|
388
|
+
metadata: action.metadata,
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Build message payload from ask action
|
|
394
|
+
*/
|
|
395
|
+
export function buildAskPayload(action: AskActionData): MessagePayload {
|
|
396
|
+
return {
|
|
397
|
+
to: resolveActionTarget(action.object),
|
|
398
|
+
body: action.question,
|
|
399
|
+
type: 'question',
|
|
400
|
+
schema: action.schema,
|
|
401
|
+
timeout: action.timeout,
|
|
402
|
+
metadata: action.metadata,
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* Build message payload from approve action
|
|
408
|
+
*/
|
|
409
|
+
export function buildApprovePayload(action: ApproveActionData): MessagePayload {
|
|
410
|
+
return {
|
|
411
|
+
to: resolveActionTarget(action.object),
|
|
412
|
+
body: action.request,
|
|
413
|
+
type: 'approval',
|
|
414
|
+
timeout: action.timeout,
|
|
415
|
+
actions: [
|
|
416
|
+
{ id: 'approve', label: 'Approve', style: 'primary', value: true },
|
|
417
|
+
{ id: 'reject', label: 'Reject', style: 'danger', value: false },
|
|
418
|
+
],
|
|
419
|
+
metadata: {
|
|
420
|
+
...action.metadata,
|
|
421
|
+
context: action.context,
|
|
422
|
+
},
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Resolve action target to address string
|
|
428
|
+
*/
|
|
429
|
+
function resolveActionTarget(target: Worker | Team | WorkerRef | string): string {
|
|
430
|
+
if (typeof target === 'string') return target
|
|
431
|
+
if ('contacts' in target) {
|
|
432
|
+
const address = getPrimaryAddress(target as Worker)
|
|
433
|
+
return address?.value || target.id
|
|
434
|
+
}
|
|
435
|
+
return target.id
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// =============================================================================
|
|
439
|
+
// Integration with digital-tools Message/Call types
|
|
440
|
+
// =============================================================================
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Message type mapping (from digital-tools)
|
|
444
|
+
*/
|
|
445
|
+
export const MessageTypeMapping = {
|
|
446
|
+
email: 'email',
|
|
447
|
+
sms: 'text',
|
|
448
|
+
slack: 'chat',
|
|
449
|
+
teams: 'chat',
|
|
450
|
+
discord: 'chat',
|
|
451
|
+
whatsapp: 'text',
|
|
452
|
+
telegram: 'text',
|
|
453
|
+
voice: 'voicemail', // For voicemail messages
|
|
454
|
+
} as const
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* Call type mapping (from digital-tools)
|
|
458
|
+
*/
|
|
459
|
+
export const CallTypeMapping = {
|
|
460
|
+
phone: 'phone',
|
|
461
|
+
voice: 'phone',
|
|
462
|
+
web: 'web',
|
|
463
|
+
video: 'video',
|
|
464
|
+
} as const
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* Convert worker notification to digital-tools Message format
|
|
468
|
+
*/
|
|
469
|
+
export function toDigitalToolsMessage(
|
|
470
|
+
payload: MessagePayload,
|
|
471
|
+
transport: Transport
|
|
472
|
+
): Record<string, unknown> {
|
|
473
|
+
const messageType = MessageTypeMapping[transport as keyof typeof MessageTypeMapping] || 'chat'
|
|
474
|
+
|
|
475
|
+
return {
|
|
476
|
+
type: messageType,
|
|
477
|
+
to: Array.isArray(payload.to) ? payload.to : [payload.to],
|
|
478
|
+
from: payload.from,
|
|
479
|
+
subject: payload.subject,
|
|
480
|
+
body: payload.body,
|
|
481
|
+
html: payload.html,
|
|
482
|
+
metadata: {
|
|
483
|
+
...payload.metadata,
|
|
484
|
+
workerActionType: payload.type,
|
|
485
|
+
priority: payload.priority,
|
|
486
|
+
},
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* Convert digital-tools Message to worker notification format
|
|
492
|
+
*/
|
|
493
|
+
export function fromDigitalToolsMessage(
|
|
494
|
+
message: Record<string, unknown>
|
|
495
|
+
): Partial<MessagePayload> {
|
|
496
|
+
return {
|
|
497
|
+
to: message.to as string | string[],
|
|
498
|
+
from: message.from as string | undefined,
|
|
499
|
+
subject: message.subject as string | undefined,
|
|
500
|
+
body: message.body as string,
|
|
501
|
+
html: message.html as string | undefined,
|
|
502
|
+
metadata: message.metadata as Record<string, unknown> | undefined,
|
|
503
|
+
}
|
|
504
|
+
}
|