@botpress/adk-cli 1.19.0-beta.3 → 1.19.0-beta.5

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 (81) hide show
  1. package/assets/ui-dist/assets/{index-CSTz-oTK.js → index-B3b7PPgV.js} +4 -4
  2. package/{dist/index-DNqXHLNi-27nvpkee.js → assets/ui-dist/assets/index-BESZeTO5.js} +2 -2
  3. package/{dist/index-DAztRXeA-vr85xnxs.css → assets/ui-dist/assets/index-DIFGtVmI.css} +1 -1
  4. package/{dist/index-DfjXY3Oo-szsanhnt.js → assets/ui-dist/assets/index-a3ZL0_Jr.js} +2 -2
  5. package/assets/ui-dist/index.html +2 -2
  6. package/dist/{README-wjb7z7f0.md → README-824wa4jj.md} +1 -1
  7. package/dist/SKILL-75ym6tcj.md +257 -0
  8. package/dist/SKILL-chnwzmt1.md +548 -0
  9. package/dist/SKILL-d4bs53y3.md +244 -0
  10. package/dist/SKILL-h4b2f1n9.md +114 -0
  11. package/dist/SKILL-hbw5nt95.md +111 -0
  12. package/dist/actions-h7hxxvxr.md +823 -0
  13. package/dist/adk-build-emhwd0tg.md +39 -0
  14. package/dist/adk-debug-yrrdtpmb.md +23 -0
  15. package/dist/adk-dev-console-7z9rtjpy.md +17 -0
  16. package/dist/adk-document-ras6zzzh.md +68 -0
  17. package/dist/adk-eval-vx76dwq0.md +17 -0
  18. package/dist/adk-explain-fcsaw852.md +22 -0
  19. package/dist/adk-init-9kmxmbbe.md +30 -0
  20. package/dist/adk-ship-dybzn884.md +29 -0
  21. package/dist/adk-test-xq67savs.md +27 -0
  22. package/dist/adk-validate-1p4skv4m.md +31 -0
  23. package/dist/advanced-patterns-z86m9h1a.md +669 -0
  24. package/dist/agent-config-1aqvkrgf.md +450 -0
  25. package/dist/agent-steps-zj4c1n9t.md +115 -0
  26. package/dist/agent0-assets/skills/adk/SKILL.md +5 -5
  27. package/dist/agent0-assets/skills/adk/references/cli.md +265 -24
  28. package/dist/agent0-assets/skills/adk-debugger/SKILL.md +5 -5
  29. package/dist/agent0-assets/skills/adk-debugger/references/common-failures.md +1 -1
  30. package/dist/agent0-assets/skills/adk-debugger/references/debug-workflow.md +3 -3
  31. package/dist/agent0-assets/skills/adk-debugger/references/traces-and-logs.md +15 -7
  32. package/dist/assets-q7jt8r2q.md +237 -0
  33. package/dist/autonomous-execution-fymc12e5.md +747 -0
  34. package/dist/cli-c31e06yr.md +1334 -0
  35. package/dist/cli.js +963 -548
  36. package/dist/commands.json +24 -3
  37. package/dist/common-failures-ht29w2db.md +231 -0
  38. package/dist/component-registry-bbpw0see.md +43 -0
  39. package/dist/context-api-760cvh0h.md +461 -0
  40. package/dist/conversation-analysis-8ka4nrm4.md +420 -0
  41. package/dist/conversation-lifecycle-4seqqjc1.md +311 -0
  42. package/dist/conversations-gwfvxaee.md +1111 -0
  43. package/dist/custom-components-y5wdgpey.md +167 -0
  44. package/dist/debug-workflow-vz84q80v.md +239 -0
  45. package/dist/desk-k54ktvsd.md +852 -0
  46. package/dist/doc-standards-ck6ax2jd.md +124 -0
  47. package/dist/eval-format-7n9brja4.md +354 -0
  48. package/dist/evals-y1zcr1mc.md +11 -0
  49. package/dist/explain-config-1yaq3zzd.md +424 -0
  50. package/dist/files-dzt0wxn3.md +918 -0
  51. package/dist/{index-gqxgqnyz.html → index-3t354nbw.html} +2 -2
  52. package/dist/{index-CSTz-oTK-mdfh47r8.js → index-B3b7PPgV-zetkb01w.js} +4 -4
  53. package/{assets/ui-dist/assets/index-DNqXHLNi.js → dist/index-BESZeTO5-2rpmcefa.js} +2 -2
  54. package/{assets/ui-dist/assets/index-DAztRXeA.css → dist/index-DIFGtVmI-d4dhjg97.css} +1 -1
  55. package/{assets/ui-dist/assets/index-DfjXY3Oo.js → dist/index-a3ZL0_Jr-q145h35p.js} +2 -2
  56. package/dist/integration-actions-xang7tma.md +659 -0
  57. package/dist/integrations-k5ss07f4.md +266 -0
  58. package/dist/interfaces-6t0bpxs4.md +97 -0
  59. package/dist/knowledge-bases-20rg8p5c.md +456 -0
  60. package/dist/llm-debugging-76ng8rzm.md +209 -0
  61. package/dist/mcp-server-n1asyzhv.md +112 -0
  62. package/dist/messages-gkkg0b54.md +769 -0
  63. package/dist/model-configuration-f273kgd0.md +201 -0
  64. package/dist/multi-agent-dashboard-1mdfjdts.md +70 -0
  65. package/dist/pages-xn18xn73.md +273 -0
  66. package/dist/patterns-mistakes-5vb99dhf.md +469 -0
  67. package/dist/plugins-ttnx8f49.md +280 -0
  68. package/dist/tables-x45t36dd.md +1136 -0
  69. package/dist/tags-46td3qrg.md +516 -0
  70. package/dist/test-patterns-hj47w4nc.md +355 -0
  71. package/dist/testing-workflow-2vkp932f.md +225 -0
  72. package/dist/tools-wk7bq24z.md +581 -0
  73. package/dist/trace-summarization-hdyx1c2e.md +313 -0
  74. package/dist/traces-and-logs-f2kjfh19.md +203 -0
  75. package/dist/triggers-4j2cc86x.md +719 -0
  76. package/dist/ui-server-entry.js +977 -162
  77. package/dist/workflow-steps-mrdrf1c5.md +851 -0
  78. package/dist/workflows-gadx3s69.md +1408 -0
  79. package/dist/zai-agent-reference-e6644aad.md +454 -0
  80. package/dist/zai-complete-guide-mnna5d6f.md +1408 -0
  81. package/package.json +4 -4
@@ -0,0 +1,719 @@
1
+ # Triggers
2
+
3
+ Triggers allow your bot to react to events from the bot itself or integrated services. They enable event-driven automation and workflow orchestration.
4
+
5
+ > **⚠️ IMPORTANT:** Always verify integration events exist before using them! Use `adk info <integration> --events` to discover real events. Integration events change between versions.
6
+ >
7
+ > **⚠️ Dev-mode limitation:** `adk dev` is not a perfect mirror of production for every integration event flow. Some private or custom integration events may not register or route locally even when the event name is valid. If an event-driven flow works in docs but not in local dev, verify the event first, then test against a deployed bot before assuming your trigger code is wrong.
8
+
9
+ ## Basic Concepts
10
+
11
+ ### What are Triggers?
12
+ - **Event handlers**: React to bot or integration events
13
+ - **Automated**: Execute automatically when events occur
14
+ - **Flexible**: Can start workflows, update tables, or perform any action
15
+
16
+ ### File Location
17
+ - **Location**: `src/triggers/*.ts`
18
+ - **Auto-registration**: Files automatically subscribe to specified events
19
+
20
+ ## Creating Triggers
21
+
22
+ ### Basic Structure
23
+
24
+ ```typescript
25
+ import { Trigger } from "@botpress/runtime";
26
+
27
+ export default new Trigger({
28
+ name: "myTrigger",
29
+ description: "Handles user creation events",
30
+ events: ["user.created"], // Events to subscribe to
31
+
32
+ handler: async ({ event }) => {
33
+ console.log(event.type); // "user.created"
34
+ console.log(event.payload); // Event data
35
+
36
+ // React to the event
37
+ await handleUserCreated(event.payload);
38
+ }
39
+ });
40
+ ```
41
+
42
+ ### Multiple Events
43
+
44
+ Subscribe to multiple events in one trigger:
45
+
46
+ ```typescript
47
+ export default new Trigger({
48
+ name: "userEvents",
49
+ description: "Handles all user-related events",
50
+ events: [
51
+ "user.created",
52
+ "user.updated",
53
+ "user.deleted"
54
+ ],
55
+
56
+ handler: async ({ event }) => {
57
+ switch (event.type) {
58
+ case "user.created":
59
+ await handleUserCreated(event.payload);
60
+ break;
61
+ case "user.updated":
62
+ await handleUserUpdated(event.payload);
63
+ break;
64
+ case "user.deleted":
65
+ await handleUserDeleted(event.payload);
66
+ break;
67
+ }
68
+ }
69
+ });
70
+ ```
71
+
72
+ ## Event Types
73
+
74
+ ### Bot Events
75
+
76
+ Standard events emitted by the bot:
77
+
78
+ ```typescript
79
+ // User events
80
+ "user.created" // New user created
81
+ "user.updated" // User information updated
82
+ "user.deleted" // User deleted
83
+
84
+ // Conversation events
85
+ "conversation.started" // New conversation started
86
+ "conversation.ended" // Conversation ended
87
+ "message.created" // New message in conversation
88
+
89
+ // Workflow events
90
+ "workflow.started" // Workflow instance started
91
+ "workflow.completed" // Workflow completed successfully
92
+ "workflow.failed" // Workflow failed
93
+
94
+ // Bot lifecycle events
95
+ "bot.started" // Bot started
96
+ "bot.stopped" // Bot stopped
97
+ ```
98
+
99
+ ### Integration Events
100
+
101
+ Events from integrated services use the pattern `integrationName:eventName`.
102
+
103
+ **IMPORTANT:** Always verify events exist using `adk info <integration> --events` before using them.
104
+
105
+ ```typescript
106
+ // Intercom events (real events from vertical-one)
107
+ "intercom:conversationEvent" // Fires on create/update/delete
108
+ "intercom:contactEvent" // Contact created/updated
109
+ "intercom:adminEvent" // Admin changes
110
+
111
+ // Slack events (verified with adk info slack --events)
112
+ "slack:reactionAdded"
113
+ "slack:reactionRemoved"
114
+ "slack:memberJoinedChannel"
115
+ "slack:memberJoinedWorkspace"
116
+ "slack:memberLeftChannel"
117
+ "slack:workflowWebhook"
118
+
119
+ // Linear events (verified with adk info linear --events)
120
+ "linear:issueCreated"
121
+ "linear:issueUpdated"
122
+ "linear:issueDeleted"
123
+
124
+ // GitHub events (verified with adk info github --events)
125
+ "github:issueOpened"
126
+ "github:pullRequestOpened"
127
+ "github:pullRequestMerged"
128
+ "github:pullRequestReviewSubmitted"
129
+
130
+ // Webchat events (verified with adk info webchat --events)
131
+ "webchat:conversationStarted"
132
+ "webchat:trigger"
133
+ ```
134
+
135
+ **How to discover events:**
136
+ ```bash
137
+ # Search for an integration
138
+ adk search email
139
+
140
+ # Get all events for an integration
141
+ adk info slack --events
142
+ adk info linear --events
143
+ adk info github --events
144
+ ```
145
+
146
+ Checking `adk info <integration> --events` confirms the event exists, but it does not guarantee that every event source behaves the same in `adk dev` as it does after deployment.
147
+
148
+ ## Trigger Handlers
149
+
150
+ ### Starting Workflows
151
+
152
+ Common pattern: Start a workflow when an event occurs:
153
+
154
+ ```typescript
155
+ import { Trigger } from "@botpress/runtime";
156
+ import { OnboardingWorkflow } from "../workflows/onboarding";
157
+
158
+ export default new Trigger({
159
+ name: "userOnboarding",
160
+ description: "Start onboarding when user is created",
161
+ events: ["user.created"],
162
+
163
+ handler: async ({ event }) => {
164
+ const { userId, email, name } = event.payload;
165
+
166
+ // Start onboarding workflow
167
+ const instance = await OnboardingWorkflow.start({
168
+ userId,
169
+ email,
170
+ name,
171
+ createdAt: new Date()
172
+ });
173
+
174
+ console.log(`Started onboarding for ${userId}: ${instance.id}`);
175
+ }
176
+ });
177
+ ```
178
+
179
+ ### Updating Tables
180
+
181
+ Store event data in tables:
182
+
183
+ ```typescript
184
+ import { Trigger } from "@botpress/runtime";
185
+ import { EventLogTable } from "../tables/EventLog";
186
+
187
+ export default new Trigger({
188
+ name: "eventLogger",
189
+ description: "Log all events to database",
190
+ events: [
191
+ "user.created",
192
+ "user.updated",
193
+ "conversation.started",
194
+ "workflow.completed"
195
+ ],
196
+
197
+ handler: async ({ event }) => {
198
+ // Store event in table
199
+ await EventLogTable.createRows({
200
+ rows: [{
201
+ type: event.type,
202
+ payload: event.payload,
203
+ timestamp: new Date(),
204
+ metadata: {
205
+ source: event.source || "bot",
206
+ version: event.version || "1.0"
207
+ }
208
+ }]
209
+ });
210
+ }
211
+ });
212
+ ```
213
+
214
+ ### Calling Actions
215
+
216
+ Execute bot actions or integration actions in response to events:
217
+
218
+ ```typescript
219
+ import { Trigger } from "@botpress/runtime";
220
+ import { actions } from "@botpress/runtime";
221
+
222
+ export default new Trigger({
223
+ name: "notificationSender",
224
+ description: "Send email notifications for important events",
225
+ events: ["workflow.failed", "user.deleted"],
226
+
227
+ handler: async ({ event }) => {
228
+ // Call integration action (e.g., SendGrid)
229
+ // First add the integration: adk add sendgrid
230
+ await actions.sendgrid.sendEmail({
231
+ to: "admin@example.com",
232
+ from: "bot@example.com",
233
+ subject: `Alert: ${event.type}`,
234
+ content: `Event occurred: ${JSON.stringify(event.payload)}`
235
+ });
236
+ }
237
+ });
238
+ ```
239
+
240
+ **Note:** The `actions` object provides access to:
241
+ - **Bot actions**: `actions.myAction()` - your custom actions from `src/actions/`
242
+ - **Integration actions**: `actions.integrationName.actionName()` - actions from installed integrations
243
+
244
+ ## Integration Event Examples
245
+
246
+ ### Intercom Integration
247
+
248
+ Real-world example from vertical-one bot:
249
+
250
+ ```typescript
251
+ import { Trigger } from "@botpress/runtime";
252
+ import {
253
+ syncSingleConversation,
254
+ deleteConversation,
255
+ } from "../utils/syncConversation";
256
+
257
+ export default new Trigger({
258
+ name: "onIntercomUpdate",
259
+ description:
260
+ "Updates the Intercom tables in realtime when conversations are created or messages are sent",
261
+ events: ["intercom:conversationEvent"],
262
+
263
+ handler: async ({ event }) => {
264
+ const { eventType, conversationId } = event.payload;
265
+
266
+ console.log(
267
+ `Intercom event: ${eventType} for conversation ${conversationId}`
268
+ );
269
+
270
+ try {
271
+ if (eventType === "deleted") {
272
+ // Delete the conversation and its messages
273
+ await deleteConversation(conversationId);
274
+ } else {
275
+ // Sync the conversation with all its data
276
+ await syncSingleConversation(conversationId);
277
+ }
278
+ } catch (error) {
279
+ console.error(
280
+ `Failed to handle ${eventType} event for conversation ${conversationId}:`,
281
+ error
282
+ );
283
+ throw error;
284
+ }
285
+ },
286
+ });
287
+ ```
288
+
289
+ ### Linear Integration
290
+
291
+ Real example from ADK source code:
292
+
293
+ ```typescript
294
+ import { Trigger } from "@botpress/runtime";
295
+ import { LinearIssueTable } from "../tables/LinearIssues";
296
+
297
+ export default new Trigger({
298
+ name: "onLinearIssueUpdate",
299
+ description: "Updates the Linear Issue Table when issues change",
300
+ events: [
301
+ "linear:issueCreated",
302
+ "linear:issueUpdated",
303
+ "linear:issueDeleted"
304
+ ],
305
+
306
+ handler: async ({ event }) => {
307
+ if (event.type === "linear:issueDeleted") {
308
+ await LinearIssueTable.deleteRows({
309
+ linearId: event.payload.id
310
+ });
311
+ } else if (event.type === "linear:issueCreated") {
312
+ await LinearIssueTable.createRows({
313
+ rows: [{
314
+ linearId: event.payload.linearIds?.issueId,
315
+ content: `# ${event.payload.title}\n\n${event.payload.description}`,
316
+ issue: event.payload,
317
+ linearUpdatedAt: event.payload.updatedAt
318
+ }]
319
+ });
320
+ } else if (event.type === "linear:issueUpdated") {
321
+ await LinearIssueTable.upsertRows({
322
+ rows: [{
323
+ linearId: event.payload.linearIds?.issueId,
324
+ content: `# ${event.payload.title}\n\n${event.payload.description}`,
325
+ issue: event.payload,
326
+ linearUpdatedAt: event.payload.updatedAt
327
+ }],
328
+ keyColumn: "linearId"
329
+ });
330
+ }
331
+ }
332
+ });
333
+ ```
334
+
335
+ ### Slack Integration
336
+
337
+ ```typescript
338
+ import { Trigger } from "@botpress/runtime";
339
+ import { SlackActivityTable } from "../tables/SlackActivity";
340
+
341
+ export default new Trigger({
342
+ name: "slackActivityMonitor",
343
+ description: "Monitor Slack reactions and member activity",
344
+ events: [
345
+ "slack:reactionAdded",
346
+ "slack:memberJoinedChannel"
347
+ ],
348
+
349
+ handler: async ({ event }) => {
350
+ if (event.type === "slack:reactionAdded") {
351
+ const { reaction, user, item } = event.payload;
352
+
353
+ // Log important reactions to table
354
+ if (reaction === "fire" || reaction === "star" || reaction === "eyes") {
355
+ await SlackActivityTable.createRows({
356
+ rows: [{
357
+ type: "reaction",
358
+ reaction: reaction,
359
+ user: user,
360
+ messageId: item.ts,
361
+ channelId: item.channel,
362
+ timestamp: new Date()
363
+ }]
364
+ });
365
+ }
366
+ }
367
+
368
+ if (event.type === "slack:memberJoinedChannel") {
369
+ const { user, channel } = event.payload;
370
+
371
+ // Log new member joins
372
+ await SlackActivityTable.createRows({
373
+ rows: [{
374
+ type: "member_join",
375
+ user: user,
376
+ channelId: channel,
377
+ timestamp: new Date()
378
+ }]
379
+ });
380
+ }
381
+ }
382
+ });
383
+ ```
384
+
385
+ ## Advanced Patterns
386
+
387
+ ### Conditional Processing
388
+
389
+ Process events based on conditions:
390
+
391
+ ```typescript
392
+ export default new Trigger({
393
+ name: "conditionalProcessor",
394
+ events: ["user.created"],
395
+
396
+ handler: async ({ event }) => {
397
+ const { email, source, metadata } = event.payload;
398
+
399
+ // Only process certain users
400
+ if (!email.endsWith("@company.com")) {
401
+ console.log("Skipping external user");
402
+ return;
403
+ }
404
+
405
+ // Different handling based on source
406
+ if (source === "api") {
407
+ await handleApiUser(event.payload);
408
+ } else if (source === "signup") {
409
+ await handleSignupUser(event.payload);
410
+ }
411
+
412
+ // Check metadata flags
413
+ if (metadata?.requiresApproval) {
414
+ await startApprovalWorkflow(event.payload);
415
+ }
416
+ }
417
+ });
418
+ ```
419
+
420
+ ### Event Aggregation
421
+
422
+ Collect and batch process events:
423
+
424
+ ```typescript
425
+ import { Trigger } from "@botpress/runtime";
426
+ import { EventBatchTable } from "../tables/EventBatch";
427
+
428
+ export default new Trigger({
429
+ name: "eventAggregator",
430
+ events: ["metrics.recorded"],
431
+
432
+ handler: async ({ event }) => {
433
+ // Store event for batching
434
+ await EventBatchTable.createRows({
435
+ rows: [{
436
+ type: event.type,
437
+ data: event.payload,
438
+ processed: false,
439
+ timestamp: new Date()
440
+ }]
441
+ });
442
+
443
+ // Check if we should process batch
444
+ const { rows } = await EventBatchTable.findRows({
445
+ where: { processed: false },
446
+ limit: 100
447
+ });
448
+
449
+ if (rows.length >= 100) {
450
+ // Process batch
451
+ await processBatch(rows);
452
+
453
+ // Mark as processed
454
+ const ids = rows.map(r => r.id);
455
+ await EventBatchTable.updateRows({
456
+ where: { id: { $in: ids } },
457
+ updates: { processed: true }
458
+ });
459
+ }
460
+ }
461
+ });
462
+ ```
463
+
464
+ ### Workflow Orchestration
465
+
466
+ Chain workflows based on events:
467
+
468
+ ```typescript
469
+ export default new Trigger({
470
+ name: "workflowOrchestrator",
471
+ events: ["workflow.completed"],
472
+
473
+ handler: async ({ event }) => {
474
+ const { workflowName, output } = event.payload;
475
+
476
+ // Chain workflows based on completion
477
+ switch (workflowName) {
478
+ case "dataCollection":
479
+ // Start processing workflow
480
+ await ProcessingWorkflow.start({
481
+ data: output.collectedData
482
+ });
483
+ break;
484
+
485
+ case "processing":
486
+ // Start validation workflow
487
+ await ValidationWorkflow.start({
488
+ processedData: output.result
489
+ });
490
+ break;
491
+
492
+ case "validation":
493
+ // Start final reporting workflow
494
+ if (output.isValid) {
495
+ await ReportingWorkflow.start({
496
+ data: output.validatedData
497
+ });
498
+ }
499
+ break;
500
+ }
501
+ }
502
+ });
503
+ ```
504
+
505
+ ### Error Recovery
506
+
507
+ Handle failed events:
508
+
509
+ ```typescript
510
+ export default new Trigger({
511
+ name: "errorRecovery",
512
+ events: ["workflow.failed", "integration:error"],
513
+
514
+ handler: async ({ event }) => {
515
+ const { error, context, retryCount = 0 } = event.payload;
516
+
517
+ // Log error
518
+ await ErrorLogTable.createRows({
519
+ rows: [{
520
+ type: event.type,
521
+ error: error.message,
522
+ stack: error.stack,
523
+ context,
524
+ timestamp: new Date()
525
+ }]
526
+ });
527
+
528
+ // Attempt recovery
529
+ if (retryCount < 3) {
530
+ // Retry with backoff
531
+ setTimeout(async () => {
532
+ await RetryWorkflow.start({
533
+ originalEvent: event,
534
+ retryCount: retryCount + 1
535
+ });
536
+ }, Math.pow(2, retryCount) * 1000);
537
+ } else {
538
+ // Send alert after max retries
539
+ await actions.sendAlert({
540
+ severity: "critical",
541
+ title: "Max retries exceeded",
542
+ details: { event, error }
543
+ });
544
+ }
545
+ }
546
+ });
547
+ ```
548
+
549
+ ## Best Practices
550
+
551
+ ### 1. Use Descriptive Names
552
+ ```typescript
553
+ // ✅ Good
554
+ export default new Trigger({
555
+ name: "linearIssueSync",
556
+ description: "Syncs Linear issues to internal tracking"
557
+ });
558
+
559
+ // ❌ Bad
560
+ export default new Trigger({
561
+ name: "trigger1",
562
+ description: "Does stuff"
563
+ });
564
+ ```
565
+
566
+ ### 2. Handle Errors Gracefully
567
+ ```typescript
568
+ handler: async ({ event }) => {
569
+ try {
570
+ await processEvent(event);
571
+ } catch (error) {
572
+ console.error(`Failed to process ${event.type}:`, error);
573
+
574
+ // Store error for debugging
575
+ await ErrorTable.createRows({
576
+ rows: [{
577
+ trigger: "myTrigger",
578
+ event: event.type,
579
+ error: error.message,
580
+ timestamp: new Date()
581
+ }]
582
+ });
583
+
584
+ // Don't re-throw unless you want to retry
585
+ }
586
+ }
587
+ ```
588
+
589
+ ### 3. Avoid Heavy Processing
590
+ ```typescript
591
+ handler: async ({ event }) => {
592
+ // ✅ Good: Start async workflow
593
+ await HeavyProcessingWorkflow.start({
594
+ eventData: event.payload
595
+ });
596
+
597
+ // ❌ Bad: Long-running synchronous processing
598
+ // const result = await performHeavyComputation(event.payload);
599
+ }
600
+ ```
601
+
602
+ ### 4. Use Event Patterns
603
+ ```typescript
604
+ // Group related events from multiple integrations
605
+ export default new Trigger({
606
+ name: "issueTracker",
607
+ events: [
608
+ "linear:issueCreated",
609
+ "linear:issueUpdated",
610
+ "github:issueOpened",
611
+ "github:pullRequestOpened"
612
+ ],
613
+
614
+ handler: async ({ event }) => {
615
+ const [integration, action] = event.type.split(":");
616
+
617
+ // Common processing for all issue-related events
618
+ await IssueTrackingTable.createRows({
619
+ rows: [{
620
+ source: integration,
621
+ eventType: action,
622
+ data: event.payload,
623
+ timestamp: new Date()
624
+ }]
625
+ });
626
+ }
627
+ });
628
+ ```
629
+
630
+ ### 5. Document Event Payloads
631
+ ```typescript
632
+ /**
633
+ * Handles user creation events
634
+ *
635
+ * Expected payload:
636
+ * {
637
+ * userId: string
638
+ * email: string
639
+ * name: string
640
+ * source: "signup" | "api" | "admin"
641
+ * metadata?: Record<string, any>
642
+ * }
643
+ */
644
+ export default new Trigger({
645
+ name: "userCreatedHandler",
646
+ events: ["user.created"],
647
+
648
+ handler: async ({ event }) => {
649
+ const { userId, email, name, source } = event.payload;
650
+ // Process with confidence in payload structure
651
+ }
652
+ });
653
+ ```
654
+
655
+ ## Common Patterns
656
+
657
+ ### Audit Trail
658
+ ```typescript
659
+ export default new Trigger({
660
+ name: "auditTrail",
661
+ events: [
662
+ "user.created",
663
+ "user.updated",
664
+ "user.deleted",
665
+ "conversation.started"
666
+ ],
667
+
668
+ handler: async ({ event }) => {
669
+ await AuditTable.createRows({
670
+ rows: [{
671
+ eventType: event.type,
672
+ payload: event.payload,
673
+ userId: event.payload.userId || event.userId,
674
+ timestamp: new Date()
675
+ }]
676
+ });
677
+ }
678
+ });
679
+ ```
680
+
681
+ ### Notification System
682
+ ```typescript
683
+ export default new Trigger({
684
+ name: "notifications",
685
+ events: [
686
+ "workflow.failed",
687
+ "user.deleted",
688
+ "integration:error"
689
+ ],
690
+
691
+ handler: async ({ event }) => {
692
+ const notifications = {
693
+ "workflow.failed": {
694
+ channel: "slack",
695
+ priority: "high",
696
+ template: "workflow-failure"
697
+ },
698
+ "user.deleted": {
699
+ channel: "email",
700
+ priority: "normal",
701
+ template: "user-deleted"
702
+ },
703
+ "integration:error": {
704
+ channel: "pagerduty",
705
+ priority: "critical",
706
+ template: "integration-error"
707
+ }
708
+ };
709
+
710
+ const config = notifications[event.type];
711
+ if (config) {
712
+ await actions.sendNotification({
713
+ ...config,
714
+ data: event.payload
715
+ });
716
+ }
717
+ }
718
+ });
719
+ ```