@xano/developer-mcp 1.0.7 → 1.0.8
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/README.md +12 -0
- package/dist/index.js +7 -1
- package/package.json +1 -1
- package/xanoscript_docs/triggers.md +354 -52
package/README.md
CHANGED
|
@@ -39,6 +39,18 @@ Add to your Claude Desktop configuration file:
|
|
|
39
39
|
}
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
+
## Checking Your Version
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
npx @xano/developer-mcp --version
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
If installed from source:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
node dist/index.js --version
|
|
52
|
+
```
|
|
53
|
+
|
|
42
54
|
## Installation from Source
|
|
43
55
|
|
|
44
56
|
### Prerequisites
|
package/dist/index.js
CHANGED
|
@@ -11,6 +11,12 @@ import { getSchemeFromContent } from "@xano/xanoscript-language-server/utils.js"
|
|
|
11
11
|
import { generateInitWorkspaceTemplate } from "./templates/init-workspace.js";
|
|
12
12
|
const __filename = fileURLToPath(import.meta.url);
|
|
13
13
|
const __dirname = dirname(__filename);
|
|
14
|
+
const pkg = JSON.parse(readFileSync(join(__dirname, "..", "package.json"), "utf-8"));
|
|
15
|
+
const SERVER_VERSION = pkg.version;
|
|
16
|
+
if (process.argv.includes("--version") || process.argv.includes("-v")) {
|
|
17
|
+
console.log(SERVER_VERSION);
|
|
18
|
+
process.exit(0);
|
|
19
|
+
}
|
|
14
20
|
const XANOSCRIPT_DOCS_V2 = {
|
|
15
21
|
readme: {
|
|
16
22
|
file: "README.md",
|
|
@@ -357,7 +363,7 @@ function generateInitWorkspaceDoc() {
|
|
|
357
363
|
// =============================================================================
|
|
358
364
|
const server = new Server({
|
|
359
365
|
name: "xano-developer-mcp",
|
|
360
|
-
version:
|
|
366
|
+
version: SERVER_VERSION,
|
|
361
367
|
description: "MCP server for Xano Headless API documentation and XanoScript code validation",
|
|
362
368
|
}, {
|
|
363
369
|
capabilities: {
|
package/package.json
CHANGED
|
@@ -18,6 +18,157 @@ Event-driven handlers that execute in response to system events. Triggers allow
|
|
|
18
18
|
|
|
19
19
|
---
|
|
20
20
|
|
|
21
|
+
## Predefined Input Blocks
|
|
22
|
+
|
|
23
|
+
Each trigger type has a **predefined read-only input block**. These input structures are automatically provided by the system and **cannot be modified**. When creating a trigger, use the predefined input block as-is.
|
|
24
|
+
|
|
25
|
+
### Table Trigger Input
|
|
26
|
+
|
|
27
|
+
```xs
|
|
28
|
+
input {
|
|
29
|
+
json new
|
|
30
|
+
json old
|
|
31
|
+
enum action {
|
|
32
|
+
values = ["insert", "update", "delete", "truncate"]
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
text datasource
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
| Field | Type | Description |
|
|
40
|
+
|-------|------|-------------|
|
|
41
|
+
| `new` | json | The new record data (after insert/update) |
|
|
42
|
+
| `old` | json | The old record data (before update/delete) |
|
|
43
|
+
| `action` | enum | The action that triggered: `insert`, `update`, `delete`, or `truncate` |
|
|
44
|
+
| `datasource` | text | The datasource name where the change occurred |
|
|
45
|
+
|
|
46
|
+
### Agent Trigger Input
|
|
47
|
+
|
|
48
|
+
```xs
|
|
49
|
+
input {
|
|
50
|
+
object toolset {
|
|
51
|
+
schema {
|
|
52
|
+
int id
|
|
53
|
+
text name
|
|
54
|
+
text instructions
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
object[] tools {
|
|
59
|
+
schema {
|
|
60
|
+
int id
|
|
61
|
+
text name
|
|
62
|
+
text instructions
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
| Field | Type | Description |
|
|
69
|
+
|-------|------|-------------|
|
|
70
|
+
| `toolset` | object | The toolset configuration with id, name, and instructions |
|
|
71
|
+
| `tools` | object[] | Array of available tools with their id, name, and instructions |
|
|
72
|
+
|
|
73
|
+
### MCP Server Trigger Input
|
|
74
|
+
|
|
75
|
+
```xs
|
|
76
|
+
input {
|
|
77
|
+
object toolset {
|
|
78
|
+
schema {
|
|
79
|
+
int id
|
|
80
|
+
text name
|
|
81
|
+
text instructions
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
object[] tools {
|
|
86
|
+
schema {
|
|
87
|
+
int id
|
|
88
|
+
text name
|
|
89
|
+
text instructions
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
| Field | Type | Description |
|
|
96
|
+
|-------|------|-------------|
|
|
97
|
+
| `toolset` | object | The toolset configuration with id, name, and instructions |
|
|
98
|
+
| `tools` | object[] | Array of available tools with their id, name, and instructions |
|
|
99
|
+
|
|
100
|
+
### Workspace Trigger Input
|
|
101
|
+
|
|
102
|
+
```xs
|
|
103
|
+
input {
|
|
104
|
+
object to_branch {
|
|
105
|
+
schema {
|
|
106
|
+
int id
|
|
107
|
+
text label
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
object from_branch {
|
|
112
|
+
schema {
|
|
113
|
+
int id
|
|
114
|
+
text label
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
enum action {
|
|
119
|
+
values = ["branch_live", "branch_merge", "branch_new"]
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
| Field | Type | Description |
|
|
125
|
+
|-------|------|-------------|
|
|
126
|
+
| `to_branch` | object | The target branch with id and label |
|
|
127
|
+
| `from_branch` | object | The source branch with id and label |
|
|
128
|
+
| `action` | enum | The branch action: `branch_live`, `branch_merge`, or `branch_new` |
|
|
129
|
+
|
|
130
|
+
### Realtime Trigger Input
|
|
131
|
+
|
|
132
|
+
```xs
|
|
133
|
+
input {
|
|
134
|
+
enum action {
|
|
135
|
+
values = ["message", "join"]
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
text channel
|
|
139
|
+
object client {
|
|
140
|
+
schema {
|
|
141
|
+
json extras
|
|
142
|
+
object permissions {
|
|
143
|
+
schema {
|
|
144
|
+
int dbo_id
|
|
145
|
+
text row_id
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
object options {
|
|
152
|
+
schema {
|
|
153
|
+
bool authenticated
|
|
154
|
+
text channel
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
json payload
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
| Field | Type | Description |
|
|
163
|
+
|-------|------|-------------|
|
|
164
|
+
| `action` | enum | The event type: `message` or `join` |
|
|
165
|
+
| `channel` | text | The channel name |
|
|
166
|
+
| `client` | object | Client information including extras and permissions |
|
|
167
|
+
| `options` | object | Channel options including authentication status |
|
|
168
|
+
| `payload` | json | The message payload data |
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
21
172
|
## Table Trigger
|
|
22
173
|
|
|
23
174
|
Executes when database table records are inserted, updated, deleted, or truncated.
|
|
@@ -33,8 +184,14 @@ table_trigger "<name>" {
|
|
|
33
184
|
description = "Description of this trigger"
|
|
34
185
|
tags = ["tag1", "tag2"]
|
|
35
186
|
|
|
187
|
+
// Predefined input block - read-only, do not modify
|
|
36
188
|
input {
|
|
37
|
-
|
|
189
|
+
json new
|
|
190
|
+
json old
|
|
191
|
+
enum action {
|
|
192
|
+
values = ["insert", "update", "delete", "truncate"]
|
|
193
|
+
}
|
|
194
|
+
text datasource
|
|
38
195
|
}
|
|
39
196
|
|
|
40
197
|
stack {
|
|
@@ -50,7 +207,7 @@ table_trigger "<name>" {
|
|
|
50
207
|
| Clause | Description |
|
|
51
208
|
|--------|-------------|
|
|
52
209
|
| `table` | The database table name to monitor |
|
|
53
|
-
| `input` |
|
|
210
|
+
| `input` | Predefined input block (read-only) |
|
|
54
211
|
| `stack` | Logic to execute when triggered |
|
|
55
212
|
|
|
56
213
|
### Optional Clauses
|
|
@@ -83,15 +240,24 @@ table_trigger "audit_user_changes" {
|
|
|
83
240
|
description = "Log all changes to user records"
|
|
84
241
|
datasources = ["main_db"]
|
|
85
242
|
|
|
243
|
+
// Input block is predefined and read-only - do not modify
|
|
86
244
|
input {
|
|
245
|
+
json new
|
|
246
|
+
json old
|
|
247
|
+
enum action {
|
|
248
|
+
values = ["insert", "update", "delete", "truncate"]
|
|
249
|
+
}
|
|
250
|
+
text datasource
|
|
87
251
|
}
|
|
88
252
|
|
|
89
253
|
stack {
|
|
90
254
|
db.add "audit_log" {
|
|
91
255
|
data = {
|
|
92
256
|
table_name: "user",
|
|
93
|
-
action: $
|
|
94
|
-
|
|
257
|
+
action: $input.action,
|
|
258
|
+
old_data: $input.old,
|
|
259
|
+
new_data: $input.new,
|
|
260
|
+
datasource: $input.datasource,
|
|
95
261
|
timestamp: now
|
|
96
262
|
}
|
|
97
263
|
}
|
|
@@ -117,8 +283,30 @@ realtime_trigger "<name>" {
|
|
|
117
283
|
description = "Description of this trigger"
|
|
118
284
|
tags = ["tag1", "tag2"]
|
|
119
285
|
|
|
286
|
+
// Predefined input block - read-only, do not modify
|
|
120
287
|
input {
|
|
121
|
-
|
|
288
|
+
enum action {
|
|
289
|
+
values = ["message", "join"]
|
|
290
|
+
}
|
|
291
|
+
text channel
|
|
292
|
+
object client {
|
|
293
|
+
schema {
|
|
294
|
+
json extras
|
|
295
|
+
object permissions {
|
|
296
|
+
schema {
|
|
297
|
+
int dbo_id
|
|
298
|
+
text row_id
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
object options {
|
|
304
|
+
schema {
|
|
305
|
+
bool authenticated
|
|
306
|
+
text channel
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
json payload
|
|
122
310
|
}
|
|
123
311
|
|
|
124
312
|
stack {
|
|
@@ -136,7 +324,7 @@ realtime_trigger "<name>" {
|
|
|
136
324
|
| Clause | Description |
|
|
137
325
|
|--------|-------------|
|
|
138
326
|
| `channel` | The real-time channel to monitor |
|
|
139
|
-
| `input` |
|
|
327
|
+
| `input` | Predefined input block (read-only) |
|
|
140
328
|
| `stack` | Logic to execute when triggered |
|
|
141
329
|
| `response` | Value to return to the client |
|
|
142
330
|
|
|
@@ -166,21 +354,43 @@ realtime_trigger "chat_message_handler" {
|
|
|
166
354
|
active = true
|
|
167
355
|
description = "Handle chat room messages and joins"
|
|
168
356
|
|
|
357
|
+
// Input block is predefined and read-only - do not modify
|
|
169
358
|
input {
|
|
170
|
-
|
|
359
|
+
enum action {
|
|
360
|
+
values = ["message", "join"]
|
|
361
|
+
}
|
|
362
|
+
text channel
|
|
363
|
+
object client {
|
|
364
|
+
schema {
|
|
365
|
+
json extras
|
|
366
|
+
object permissions {
|
|
367
|
+
schema {
|
|
368
|
+
int dbo_id
|
|
369
|
+
text row_id
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
object options {
|
|
375
|
+
schema {
|
|
376
|
+
bool authenticated
|
|
377
|
+
text channel
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
json payload
|
|
171
381
|
}
|
|
172
382
|
|
|
173
383
|
stack {
|
|
174
384
|
conditional {
|
|
175
|
-
if ($
|
|
385
|
+
if ($input.action == "join") {
|
|
176
386
|
var $welcome { value = "Welcome to the chat!" }
|
|
177
387
|
}
|
|
178
388
|
else {
|
|
179
389
|
db.add "chat_message" {
|
|
180
390
|
data = {
|
|
181
|
-
channel:
|
|
391
|
+
channel: $input.channel,
|
|
182
392
|
user_id: $auth.id,
|
|
183
|
-
message: $input.message,
|
|
393
|
+
message: $input.payload.message,
|
|
184
394
|
timestamp: now
|
|
185
395
|
}
|
|
186
396
|
}
|
|
@@ -210,8 +420,23 @@ workspace_trigger "<name>" {
|
|
|
210
420
|
description = "Description of this trigger"
|
|
211
421
|
tags = ["tag1", "tag2"]
|
|
212
422
|
|
|
423
|
+
// Predefined input block - read-only, do not modify
|
|
213
424
|
input {
|
|
214
|
-
|
|
425
|
+
object to_branch {
|
|
426
|
+
schema {
|
|
427
|
+
int id
|
|
428
|
+
text label
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
object from_branch {
|
|
432
|
+
schema {
|
|
433
|
+
int id
|
|
434
|
+
text label
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
enum action {
|
|
438
|
+
values = ["branch_live", "branch_merge", "branch_new"]
|
|
439
|
+
}
|
|
215
440
|
}
|
|
216
441
|
|
|
217
442
|
stack {
|
|
@@ -226,7 +451,7 @@ workspace_trigger "<name>" {
|
|
|
226
451
|
|
|
227
452
|
| Clause | Description |
|
|
228
453
|
|--------|-------------|
|
|
229
|
-
| `input` |
|
|
454
|
+
| `input` | Predefined input block (read-only) |
|
|
230
455
|
| `stack` | Logic to execute when triggered |
|
|
231
456
|
|
|
232
457
|
### Optional Clauses
|
|
@@ -256,7 +481,23 @@ workspace_trigger "branch_notification" {
|
|
|
256
481
|
description = "Send notifications on branch events"
|
|
257
482
|
tags = ["devops", "notifications"]
|
|
258
483
|
|
|
484
|
+
// Input block is predefined and read-only - do not modify
|
|
259
485
|
input {
|
|
486
|
+
object to_branch {
|
|
487
|
+
schema {
|
|
488
|
+
int id
|
|
489
|
+
text label
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
object from_branch {
|
|
493
|
+
schema {
|
|
494
|
+
int id
|
|
495
|
+
text label
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
enum action {
|
|
499
|
+
values = ["branch_live", "branch_merge", "branch_new"]
|
|
500
|
+
}
|
|
260
501
|
}
|
|
261
502
|
|
|
262
503
|
stack {
|
|
@@ -265,8 +506,8 @@ workspace_trigger "branch_notification" {
|
|
|
265
506
|
api_key = $env.RESEND_API_KEY
|
|
266
507
|
to = "team@example.com"
|
|
267
508
|
from = "system@example.com"
|
|
268
|
-
subject = "Branch Event: " ~ $
|
|
269
|
-
message = "Branch '" ~ $
|
|
509
|
+
subject = "Branch Event: " ~ $input.action
|
|
510
|
+
message = "Branch '" ~ $input.from_branch.label ~ "' -> '" ~ $input.to_branch.label ~ "' event: " ~ $input.action
|
|
270
511
|
}
|
|
271
512
|
}
|
|
272
513
|
|
|
@@ -291,8 +532,22 @@ agent_trigger "<name>" {
|
|
|
291
532
|
docs = "Extended documentation for the trigger"
|
|
292
533
|
tags = ["tag1", "tag2"]
|
|
293
534
|
|
|
535
|
+
// Predefined input block - read-only, do not modify
|
|
294
536
|
input {
|
|
295
|
-
|
|
537
|
+
object toolset {
|
|
538
|
+
schema {
|
|
539
|
+
int id
|
|
540
|
+
text name
|
|
541
|
+
text instructions
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
object[] tools {
|
|
545
|
+
schema {
|
|
546
|
+
int id
|
|
547
|
+
text name
|
|
548
|
+
text instructions
|
|
549
|
+
}
|
|
550
|
+
}
|
|
296
551
|
}
|
|
297
552
|
|
|
298
553
|
stack {
|
|
@@ -310,7 +565,7 @@ agent_trigger "<name>" {
|
|
|
310
565
|
| Clause | Description |
|
|
311
566
|
|--------|-------------|
|
|
312
567
|
| `agent` | The AI agent name this trigger handles |
|
|
313
|
-
| `input` |
|
|
568
|
+
| `input` | Predefined input block (read-only) |
|
|
314
569
|
| `stack` | Logic to execute when triggered |
|
|
315
570
|
| `response` | Value to return |
|
|
316
571
|
|
|
@@ -341,21 +596,31 @@ agent_trigger "assistant_handler" {
|
|
|
341
596
|
description = "Handle customer assistant agent connections"
|
|
342
597
|
docs = "This trigger initializes the customer context when the agent connects"
|
|
343
598
|
|
|
599
|
+
// Input block is predefined and read-only - do not modify
|
|
344
600
|
input {
|
|
345
|
-
|
|
601
|
+
object toolset {
|
|
602
|
+
schema {
|
|
603
|
+
int id
|
|
604
|
+
text name
|
|
605
|
+
text instructions
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
object[] tools {
|
|
609
|
+
schema {
|
|
610
|
+
int id
|
|
611
|
+
text name
|
|
612
|
+
text instructions
|
|
613
|
+
}
|
|
614
|
+
}
|
|
346
615
|
}
|
|
347
616
|
|
|
348
617
|
stack {
|
|
349
|
-
|
|
350
|
-
field_name = "session_id"
|
|
351
|
-
field_value = $input.session_id
|
|
352
|
-
} as $customer
|
|
353
|
-
|
|
618
|
+
// Access toolset and tools information from the predefined input
|
|
354
619
|
var $context {
|
|
355
620
|
value = {
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
621
|
+
toolset_name: $input.toolset.name,
|
|
622
|
+
toolset_instructions: $input.toolset.instructions,
|
|
623
|
+
available_tools: $input.tools
|
|
359
624
|
}
|
|
360
625
|
}
|
|
361
626
|
}
|
|
@@ -382,8 +647,22 @@ mcp_server_trigger "<name>" {
|
|
|
382
647
|
description = "Description of this trigger"
|
|
383
648
|
tags = ["tag1", "tag2"]
|
|
384
649
|
|
|
650
|
+
// Predefined input block - read-only, do not modify
|
|
385
651
|
input {
|
|
386
|
-
|
|
652
|
+
object toolset {
|
|
653
|
+
schema {
|
|
654
|
+
int id
|
|
655
|
+
text name
|
|
656
|
+
text instructions
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
object[] tools {
|
|
660
|
+
schema {
|
|
661
|
+
int id
|
|
662
|
+
text name
|
|
663
|
+
text instructions
|
|
664
|
+
}
|
|
665
|
+
}
|
|
387
666
|
}
|
|
388
667
|
|
|
389
668
|
stack {
|
|
@@ -401,7 +680,7 @@ mcp_server_trigger "<name>" {
|
|
|
401
680
|
| Clause | Description |
|
|
402
681
|
|--------|-------------|
|
|
403
682
|
| `mcp_server` | The MCP server name this trigger handles |
|
|
404
|
-
| `input` |
|
|
683
|
+
| `input` | Predefined input block (read-only) |
|
|
405
684
|
| `stack` | Logic to execute when triggered |
|
|
406
685
|
| `response` | Value to return to the MCP client |
|
|
407
686
|
|
|
@@ -431,25 +710,31 @@ mcp_server_trigger "database_tool_handler" {
|
|
|
431
710
|
description = "Handle database tool calls from MCP clients"
|
|
432
711
|
tags = ["mcp", "database"]
|
|
433
712
|
|
|
713
|
+
// Input block is predefined and read-only - do not modify
|
|
434
714
|
input {
|
|
435
|
-
|
|
436
|
-
|
|
715
|
+
object toolset {
|
|
716
|
+
schema {
|
|
717
|
+
int id
|
|
718
|
+
text name
|
|
719
|
+
text instructions
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
object[] tools {
|
|
723
|
+
schema {
|
|
724
|
+
int id
|
|
725
|
+
text name
|
|
726
|
+
text instructions
|
|
727
|
+
}
|
|
728
|
+
}
|
|
437
729
|
}
|
|
438
730
|
|
|
439
731
|
stack {
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
elseif ($input.operation == "insert") {
|
|
447
|
-
db.add $input.params.table {
|
|
448
|
-
data = $input.params.data
|
|
449
|
-
} as $result
|
|
450
|
-
}
|
|
451
|
-
else {
|
|
452
|
-
var $result { value = {error: "Unknown operation"} }
|
|
732
|
+
// Access toolset and tools information from the predefined input
|
|
733
|
+
var $result {
|
|
734
|
+
value = {
|
|
735
|
+
server: $input.toolset.name,
|
|
736
|
+
instructions: $input.toolset.instructions,
|
|
737
|
+
tool_count: count($input.tools)
|
|
453
738
|
}
|
|
454
739
|
}
|
|
455
740
|
}
|
|
@@ -471,7 +756,14 @@ table_trigger "safe_audit" {
|
|
|
471
756
|
table = "sensitive_data"
|
|
472
757
|
actions = {insert: true, update: true, delete: true, truncate: false}
|
|
473
758
|
|
|
759
|
+
// Input block is predefined and read-only
|
|
474
760
|
input {
|
|
761
|
+
json new
|
|
762
|
+
json old
|
|
763
|
+
enum action {
|
|
764
|
+
values = ["insert", "update", "delete", "truncate"]
|
|
765
|
+
}
|
|
766
|
+
text datasource
|
|
475
767
|
}
|
|
476
768
|
|
|
477
769
|
stack {
|
|
@@ -479,7 +771,9 @@ table_trigger "safe_audit" {
|
|
|
479
771
|
try {
|
|
480
772
|
db.add "audit_log" {
|
|
481
773
|
data = {
|
|
482
|
-
action: $
|
|
774
|
+
action: $input.action,
|
|
775
|
+
new_data: $input.new,
|
|
776
|
+
old_data: $input.old,
|
|
483
777
|
timestamp: now
|
|
484
778
|
}
|
|
485
779
|
}
|
|
@@ -499,19 +793,26 @@ table_trigger "conditional_notification" {
|
|
|
499
793
|
table = "order"
|
|
500
794
|
actions = {insert: true, update: false, delete: false, truncate: false}
|
|
501
795
|
|
|
796
|
+
// Input block is predefined and read-only
|
|
502
797
|
input {
|
|
798
|
+
json new
|
|
799
|
+
json old
|
|
800
|
+
enum action {
|
|
801
|
+
values = ["insert", "update", "delete", "truncate"]
|
|
802
|
+
}
|
|
803
|
+
text datasource
|
|
503
804
|
}
|
|
504
805
|
|
|
505
806
|
stack {
|
|
506
807
|
conditional {
|
|
507
|
-
if ($
|
|
808
|
+
if ($input.new.total > 1000) {
|
|
508
809
|
util.send_email {
|
|
509
810
|
service_provider = "resend"
|
|
510
811
|
api_key = $env.RESEND_API_KEY
|
|
511
812
|
to = "sales@example.com"
|
|
512
813
|
from = "system@example.com"
|
|
513
814
|
subject = "High Value Order"
|
|
514
|
-
message = "Order #" ~ $
|
|
815
|
+
message = "Order #" ~ $input.new.id ~ " for $" ~ $input.new.total
|
|
515
816
|
}
|
|
516
817
|
}
|
|
517
818
|
}
|
|
@@ -523,10 +824,11 @@ table_trigger "conditional_notification" {
|
|
|
523
824
|
|
|
524
825
|
## Best Practices
|
|
525
826
|
|
|
526
|
-
1. **Use
|
|
527
|
-
2. **
|
|
528
|
-
3. **
|
|
529
|
-
4. **
|
|
530
|
-
5. **
|
|
531
|
-
6. **
|
|
532
|
-
7. **
|
|
827
|
+
1. **Use predefined input blocks as-is** - Each trigger type has a read-only input block that cannot be modified; use the exact structure provided
|
|
828
|
+
2. **Use descriptive names** - Indicate the event and action: `user_audit_log`, `chat_message_handler`
|
|
829
|
+
3. **Handle errors gracefully** - Use try_catch to prevent trigger failures from affecting the main operation
|
|
830
|
+
4. **Keep triggers lightweight** - Offload heavy processing to functions or tasks
|
|
831
|
+
5. **Set appropriate history** - Use `history = false` for high-frequency triggers to save storage
|
|
832
|
+
6. **Use tags** - Organize triggers with meaningful tags for easier management
|
|
833
|
+
7. **Document with description** - Always provide a description explaining the trigger's purpose
|
|
834
|
+
8. **Test thoroughly** - Triggers execute automatically, so ensure they handle edge cases
|