@xano/developer-mcp 1.0.5 → 1.0.7
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/dist/index.js +5 -0
- package/dist/templates/xanoscript-index.js +1 -0
- package/package.json +1 -1
- package/xanoscript_docs/README.md +53 -37
- package/xanoscript_docs/agents.md +13 -15
- package/xanoscript_docs/apis.md +25 -85
- package/xanoscript_docs/database.md +28 -31
- package/xanoscript_docs/ephemeral.md +5 -8
- package/xanoscript_docs/frontend.md +4 -7
- package/xanoscript_docs/functions.md +12 -63
- package/xanoscript_docs/integrations.md +5 -5
- package/xanoscript_docs/mcp-servers.md +10 -13
- package/xanoscript_docs/syntax.md +118 -48
- package/xanoscript_docs/tables.md +8 -11
- package/xanoscript_docs/tasks.md +6 -9
- package/xanoscript_docs/testing.md +5 -8
- package/xanoscript_docs/tools.md +3 -11
- package/xanoscript_docs/triggers.md +532 -0
- package/xanoscript_docs/types.md +21 -31
- package/xanoscript_docs/plan.md +0 -192
|
@@ -0,0 +1,532 @@
|
|
|
1
|
+
---
|
|
2
|
+
applyTo: "triggers/**/*.xs"
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Triggers
|
|
6
|
+
|
|
7
|
+
Event-driven handlers that execute in response to system events. Triggers allow you to react to database changes, real-time messages, workspace events, agent connections, and MCP server tool calls.
|
|
8
|
+
|
|
9
|
+
## Quick Reference
|
|
10
|
+
|
|
11
|
+
| Trigger Type | Purpose | Required Clauses |
|
|
12
|
+
|--------------|---------|------------------|
|
|
13
|
+
| `table_trigger` | React to database table changes | `table`, `input`, `stack` |
|
|
14
|
+
| `realtime_trigger` | Handle real-time channel events | `channel`, `input`, `stack`, `response` |
|
|
15
|
+
| `workspace_trigger` | React to branch lifecycle events | `input`, `stack` |
|
|
16
|
+
| `agent_trigger` | Handle AI agent connections | `agent`, `input`, `stack`, `response` |
|
|
17
|
+
| `mcp_server_trigger` | Handle MCP server tool calls | `mcp_server`, `input`, `stack`, `response` |
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Table Trigger
|
|
22
|
+
|
|
23
|
+
Executes when database table records are inserted, updated, deleted, or truncated.
|
|
24
|
+
|
|
25
|
+
### Syntax
|
|
26
|
+
|
|
27
|
+
```xs
|
|
28
|
+
table_trigger "<name>" {
|
|
29
|
+
table = "<table_name>"
|
|
30
|
+
actions = {insert: true, update: true, delete: true, truncate: false}
|
|
31
|
+
datasources = ["datasource1", "datasource2"]
|
|
32
|
+
active = true
|
|
33
|
+
description = "Description of this trigger"
|
|
34
|
+
tags = ["tag1", "tag2"]
|
|
35
|
+
|
|
36
|
+
input {
|
|
37
|
+
// Define input parameters
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
stack {
|
|
41
|
+
// Logic to execute when triggered
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
history = 100
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Required Clauses
|
|
49
|
+
|
|
50
|
+
| Clause | Description |
|
|
51
|
+
|--------|-------------|
|
|
52
|
+
| `table` | The database table name to monitor |
|
|
53
|
+
| `input` | Input parameter definitions |
|
|
54
|
+
| `stack` | Logic to execute when triggered |
|
|
55
|
+
|
|
56
|
+
### Optional Clauses
|
|
57
|
+
|
|
58
|
+
| Clause | Type | Description |
|
|
59
|
+
|--------|------|-------------|
|
|
60
|
+
| `actions` | object | Which operations trigger execution |
|
|
61
|
+
| `active` | boolean | Enable/disable the trigger |
|
|
62
|
+
| `datasources` | array | List of datasources to apply trigger to |
|
|
63
|
+
| `description` | string | Human-readable description |
|
|
64
|
+
| `history` | integer/string | History retention setting |
|
|
65
|
+
| `tags` | array | Tags for organization |
|
|
66
|
+
|
|
67
|
+
### Actions
|
|
68
|
+
|
|
69
|
+
| Action | Description |
|
|
70
|
+
|--------|-------------|
|
|
71
|
+
| `insert` | Trigger on new record creation |
|
|
72
|
+
| `update` | Trigger on record modification |
|
|
73
|
+
| `delete` | Trigger on record deletion |
|
|
74
|
+
| `truncate` | Trigger when table is truncated |
|
|
75
|
+
|
|
76
|
+
### Example
|
|
77
|
+
|
|
78
|
+
```xs
|
|
79
|
+
table_trigger "audit_user_changes" {
|
|
80
|
+
table = "user"
|
|
81
|
+
actions = {insert: true, update: true, delete: true, truncate: false}
|
|
82
|
+
active = true
|
|
83
|
+
description = "Log all changes to user records"
|
|
84
|
+
datasources = ["main_db"]
|
|
85
|
+
|
|
86
|
+
input {
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
stack {
|
|
90
|
+
db.add "audit_log" {
|
|
91
|
+
data = {
|
|
92
|
+
table_name: "user",
|
|
93
|
+
action: $trigger.action,
|
|
94
|
+
record_id: $trigger.record.id,
|
|
95
|
+
timestamp: now
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
history = 100
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Realtime Trigger
|
|
107
|
+
|
|
108
|
+
Handles events from real-time channels, such as client joins or messages.
|
|
109
|
+
|
|
110
|
+
### Syntax
|
|
111
|
+
|
|
112
|
+
```xs
|
|
113
|
+
realtime_trigger "<name>" {
|
|
114
|
+
channel = "<channel_name>"
|
|
115
|
+
actions = {join: true, message: true}
|
|
116
|
+
active = true
|
|
117
|
+
description = "Description of this trigger"
|
|
118
|
+
tags = ["tag1", "tag2"]
|
|
119
|
+
|
|
120
|
+
input {
|
|
121
|
+
// Define input parameters
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
stack {
|
|
125
|
+
// Logic to execute when triggered
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
response = $result
|
|
129
|
+
|
|
130
|
+
history = 100
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Required Clauses
|
|
135
|
+
|
|
136
|
+
| Clause | Description |
|
|
137
|
+
|--------|-------------|
|
|
138
|
+
| `channel` | The real-time channel to monitor |
|
|
139
|
+
| `input` | Input parameter definitions |
|
|
140
|
+
| `stack` | Logic to execute when triggered |
|
|
141
|
+
| `response` | Value to return to the client |
|
|
142
|
+
|
|
143
|
+
### Optional Clauses
|
|
144
|
+
|
|
145
|
+
| Clause | Type | Description |
|
|
146
|
+
|--------|------|-------------|
|
|
147
|
+
| `actions` | object | Which events trigger execution |
|
|
148
|
+
| `active` | boolean | Enable/disable the trigger |
|
|
149
|
+
| `description` | string | Human-readable description |
|
|
150
|
+
| `history` | integer/string | History retention setting |
|
|
151
|
+
| `tags` | array | Tags for organization |
|
|
152
|
+
|
|
153
|
+
### Actions
|
|
154
|
+
|
|
155
|
+
| Action | Description |
|
|
156
|
+
|--------|-------------|
|
|
157
|
+
| `join` | Trigger when a client joins the channel |
|
|
158
|
+
| `message` | Trigger when a message is received |
|
|
159
|
+
|
|
160
|
+
### Example
|
|
161
|
+
|
|
162
|
+
```xs
|
|
163
|
+
realtime_trigger "chat_message_handler" {
|
|
164
|
+
channel = "chat_room"
|
|
165
|
+
actions = {join: true, message: true}
|
|
166
|
+
active = true
|
|
167
|
+
description = "Handle chat room messages and joins"
|
|
168
|
+
|
|
169
|
+
input {
|
|
170
|
+
text message filters=trim
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
stack {
|
|
174
|
+
conditional {
|
|
175
|
+
if ($trigger.action == "join") {
|
|
176
|
+
var $welcome { value = "Welcome to the chat!" }
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
db.add "chat_message" {
|
|
180
|
+
data = {
|
|
181
|
+
channel: "chat_room",
|
|
182
|
+
user_id: $auth.id,
|
|
183
|
+
message: $input.message,
|
|
184
|
+
timestamp: now
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
var $welcome { value = null }
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
response = {status: "ok", welcome: $welcome}
|
|
193
|
+
|
|
194
|
+
history = false
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## Workspace Trigger
|
|
201
|
+
|
|
202
|
+
Executes in response to workspace branch lifecycle events.
|
|
203
|
+
|
|
204
|
+
### Syntax
|
|
205
|
+
|
|
206
|
+
```xs
|
|
207
|
+
workspace_trigger "<name>" {
|
|
208
|
+
actions = {branch_new: true, branch_merge: true, branch_live: true}
|
|
209
|
+
active = true
|
|
210
|
+
description = "Description of this trigger"
|
|
211
|
+
tags = ["tag1", "tag2"]
|
|
212
|
+
|
|
213
|
+
input {
|
|
214
|
+
// Define input parameters
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
stack {
|
|
218
|
+
// Logic to execute when triggered
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
history = 100
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Required Clauses
|
|
226
|
+
|
|
227
|
+
| Clause | Description |
|
|
228
|
+
|--------|-------------|
|
|
229
|
+
| `input` | Input parameter definitions |
|
|
230
|
+
| `stack` | Logic to execute when triggered |
|
|
231
|
+
|
|
232
|
+
### Optional Clauses
|
|
233
|
+
|
|
234
|
+
| Clause | Type | Description |
|
|
235
|
+
|--------|------|-------------|
|
|
236
|
+
| `actions` | object | Which branch events trigger execution |
|
|
237
|
+
| `active` | boolean | Enable/disable the trigger |
|
|
238
|
+
| `description` | string | Human-readable description |
|
|
239
|
+
| `history` | integer/string | History retention setting |
|
|
240
|
+
| `tags` | array | Tags for organization |
|
|
241
|
+
|
|
242
|
+
### Actions
|
|
243
|
+
|
|
244
|
+
| Action | Description |
|
|
245
|
+
|--------|-------------|
|
|
246
|
+
| `branch_new` | Trigger when a new branch is created |
|
|
247
|
+
| `branch_merge` | Trigger when a branch is merged |
|
|
248
|
+
| `branch_live` | Trigger when a branch goes live |
|
|
249
|
+
|
|
250
|
+
### Example
|
|
251
|
+
|
|
252
|
+
```xs
|
|
253
|
+
workspace_trigger "branch_notification" {
|
|
254
|
+
actions = {branch_new: true, branch_merge: true, branch_live: true}
|
|
255
|
+
active = true
|
|
256
|
+
description = "Send notifications on branch events"
|
|
257
|
+
tags = ["devops", "notifications"]
|
|
258
|
+
|
|
259
|
+
input {
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
stack {
|
|
263
|
+
util.send_email {
|
|
264
|
+
service_provider = "resend"
|
|
265
|
+
api_key = $env.RESEND_API_KEY
|
|
266
|
+
to = "team@example.com"
|
|
267
|
+
from = "system@example.com"
|
|
268
|
+
subject = "Branch Event: " ~ $trigger.action
|
|
269
|
+
message = "Branch '" ~ $trigger.branch_name ~ "' event: " ~ $trigger.action
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
history = false
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
## Agent Trigger
|
|
280
|
+
|
|
281
|
+
Handles connections and interactions with AI agents.
|
|
282
|
+
|
|
283
|
+
### Syntax
|
|
284
|
+
|
|
285
|
+
```xs
|
|
286
|
+
agent_trigger "<name>" {
|
|
287
|
+
agent = "<agent_name>"
|
|
288
|
+
actions = {connection: true}
|
|
289
|
+
active = true
|
|
290
|
+
description = "Description of this trigger"
|
|
291
|
+
docs = "Extended documentation for the trigger"
|
|
292
|
+
tags = ["tag1", "tag2"]
|
|
293
|
+
|
|
294
|
+
input {
|
|
295
|
+
// Define input parameters
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
stack {
|
|
299
|
+
// Logic to execute when triggered
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
response = $result
|
|
303
|
+
|
|
304
|
+
history = "inherit"
|
|
305
|
+
}
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### Required Clauses
|
|
309
|
+
|
|
310
|
+
| Clause | Description |
|
|
311
|
+
|--------|-------------|
|
|
312
|
+
| `agent` | The AI agent name this trigger handles |
|
|
313
|
+
| `input` | Input parameter definitions |
|
|
314
|
+
| `stack` | Logic to execute when triggered |
|
|
315
|
+
| `response` | Value to return |
|
|
316
|
+
|
|
317
|
+
### Optional Clauses
|
|
318
|
+
|
|
319
|
+
| Clause | Type | Description |
|
|
320
|
+
|--------|------|-------------|
|
|
321
|
+
| `actions` | object | Which agent events trigger execution |
|
|
322
|
+
| `active` | boolean | Enable/disable the trigger |
|
|
323
|
+
| `description` | string | Short description |
|
|
324
|
+
| `docs` | string | Extended documentation |
|
|
325
|
+
| `history` | integer/string/boolean | History retention setting |
|
|
326
|
+
| `tags` | array | Tags for organization |
|
|
327
|
+
|
|
328
|
+
### Actions
|
|
329
|
+
|
|
330
|
+
| Action | Description |
|
|
331
|
+
|--------|-------------|
|
|
332
|
+
| `connection` | Trigger on agent connection events |
|
|
333
|
+
|
|
334
|
+
### Example
|
|
335
|
+
|
|
336
|
+
```xs
|
|
337
|
+
agent_trigger "assistant_handler" {
|
|
338
|
+
agent = "customer_assistant"
|
|
339
|
+
actions = {connection: true}
|
|
340
|
+
active = true
|
|
341
|
+
description = "Handle customer assistant agent connections"
|
|
342
|
+
docs = "This trigger initializes the customer context when the agent connects"
|
|
343
|
+
|
|
344
|
+
input {
|
|
345
|
+
text session_id filters=trim
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
stack {
|
|
349
|
+
db.get "customer" {
|
|
350
|
+
field_name = "session_id"
|
|
351
|
+
field_value = $input.session_id
|
|
352
|
+
} as $customer
|
|
353
|
+
|
|
354
|
+
var $context {
|
|
355
|
+
value = {
|
|
356
|
+
customer_name: $customer.name,
|
|
357
|
+
customer_tier: $customer.tier,
|
|
358
|
+
history: $customer.support_history
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
response = $context
|
|
364
|
+
|
|
365
|
+
history = "inherit"
|
|
366
|
+
}
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
---
|
|
370
|
+
|
|
371
|
+
## MCP Server Trigger
|
|
372
|
+
|
|
373
|
+
Handles tool calls from MCP (Model Context Protocol) servers.
|
|
374
|
+
|
|
375
|
+
### Syntax
|
|
376
|
+
|
|
377
|
+
```xs
|
|
378
|
+
mcp_server_trigger "<name>" {
|
|
379
|
+
mcp_server = "<server_name>"
|
|
380
|
+
actions = {connection: true}
|
|
381
|
+
active = true
|
|
382
|
+
description = "Description of this trigger"
|
|
383
|
+
tags = ["tag1", "tag2"]
|
|
384
|
+
|
|
385
|
+
input {
|
|
386
|
+
// Define input parameters
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
stack {
|
|
390
|
+
// Logic to execute when triggered
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
response = $result
|
|
394
|
+
|
|
395
|
+
history = false
|
|
396
|
+
}
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
### Required Clauses
|
|
400
|
+
|
|
401
|
+
| Clause | Description |
|
|
402
|
+
|--------|-------------|
|
|
403
|
+
| `mcp_server` | The MCP server name this trigger handles |
|
|
404
|
+
| `input` | Input parameter definitions |
|
|
405
|
+
| `stack` | Logic to execute when triggered |
|
|
406
|
+
| `response` | Value to return to the MCP client |
|
|
407
|
+
|
|
408
|
+
### Optional Clauses
|
|
409
|
+
|
|
410
|
+
| Clause | Type | Description |
|
|
411
|
+
|--------|------|-------------|
|
|
412
|
+
| `actions` | object | Which MCP events trigger execution |
|
|
413
|
+
| `active` | boolean | Enable/disable the trigger |
|
|
414
|
+
| `description` | string | Human-readable description |
|
|
415
|
+
| `history` | integer/string/boolean | History retention setting |
|
|
416
|
+
| `tags` | array | Tags for organization |
|
|
417
|
+
|
|
418
|
+
### Actions
|
|
419
|
+
|
|
420
|
+
| Action | Description |
|
|
421
|
+
|--------|-------------|
|
|
422
|
+
| `connection` | Trigger on MCP connection events (required) |
|
|
423
|
+
|
|
424
|
+
### Example
|
|
425
|
+
|
|
426
|
+
```xs
|
|
427
|
+
mcp_server_trigger "database_tool_handler" {
|
|
428
|
+
mcp_server = "database_tools"
|
|
429
|
+
actions = {connection: true}
|
|
430
|
+
active = true
|
|
431
|
+
description = "Handle database tool calls from MCP clients"
|
|
432
|
+
tags = ["mcp", "database"]
|
|
433
|
+
|
|
434
|
+
input {
|
|
435
|
+
text operation filters=trim
|
|
436
|
+
object params
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
stack {
|
|
440
|
+
conditional {
|
|
441
|
+
if ($input.operation == "query") {
|
|
442
|
+
db.query $input.params.table {
|
|
443
|
+
where = $input.params.where
|
|
444
|
+
} as $result
|
|
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"} }
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
response = $result
|
|
458
|
+
|
|
459
|
+
history = false
|
|
460
|
+
}
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
---
|
|
464
|
+
|
|
465
|
+
## Common Patterns
|
|
466
|
+
|
|
467
|
+
### Error Handling in Triggers
|
|
468
|
+
|
|
469
|
+
```xs
|
|
470
|
+
table_trigger "safe_audit" {
|
|
471
|
+
table = "sensitive_data"
|
|
472
|
+
actions = {insert: true, update: true, delete: true, truncate: false}
|
|
473
|
+
|
|
474
|
+
input {
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
stack {
|
|
478
|
+
try_catch {
|
|
479
|
+
try {
|
|
480
|
+
db.add "audit_log" {
|
|
481
|
+
data = {
|
|
482
|
+
action: $trigger.action,
|
|
483
|
+
timestamp: now
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
catch {
|
|
488
|
+
debug.log { value = "Audit logging failed" }
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
### Conditional Trigger Logic
|
|
496
|
+
|
|
497
|
+
```xs
|
|
498
|
+
table_trigger "conditional_notification" {
|
|
499
|
+
table = "order"
|
|
500
|
+
actions = {insert: true, update: false, delete: false, truncate: false}
|
|
501
|
+
|
|
502
|
+
input {
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
stack {
|
|
506
|
+
conditional {
|
|
507
|
+
if ($trigger.record.total > 1000) {
|
|
508
|
+
util.send_email {
|
|
509
|
+
service_provider = "resend"
|
|
510
|
+
api_key = $env.RESEND_API_KEY
|
|
511
|
+
to = "sales@example.com"
|
|
512
|
+
from = "system@example.com"
|
|
513
|
+
subject = "High Value Order"
|
|
514
|
+
message = "Order #" ~ $trigger.record.id ~ " for $" ~ $trigger.record.total
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
---
|
|
523
|
+
|
|
524
|
+
## Best Practices
|
|
525
|
+
|
|
526
|
+
1. **Use descriptive names** - Indicate the event and action: `user_audit_log`, `chat_message_handler`
|
|
527
|
+
2. **Handle errors gracefully** - Use try_catch to prevent trigger failures from affecting the main operation
|
|
528
|
+
3. **Keep triggers lightweight** - Offload heavy processing to functions or tasks
|
|
529
|
+
4. **Set appropriate history** - Use `history = false` for high-frequency triggers to save storage
|
|
530
|
+
5. **Use tags** - Organize triggers with meaningful tags for easier management
|
|
531
|
+
6. **Document with description** - Always provide a description explaining the trigger's purpose
|
|
532
|
+
7. **Test thoroughly** - Triggers execute automatically, so ensure they handle edge cases
|
package/xanoscript_docs/types.md
CHANGED
|
@@ -68,8 +68,8 @@ Access inputs in stack: `$input.username`, `$input.age`
|
|
|
68
68
|
|
|
69
69
|
### text
|
|
70
70
|
```xs
|
|
71
|
-
text name filters=trim|lower
|
|
72
|
-
text bio? filters=max:500
|
|
71
|
+
text name filters=trim|lower // With filters
|
|
72
|
+
text bio? filters=max:500 // Optional, max 500 chars
|
|
73
73
|
```
|
|
74
74
|
|
|
75
75
|
### int / decimal
|
|
@@ -80,7 +80,7 @@ decimal price filters=min:0.01
|
|
|
80
80
|
|
|
81
81
|
### bool
|
|
82
82
|
```xs
|
|
83
|
-
bool is_active?=true
|
|
83
|
+
bool is_active?=true // Defaults to true
|
|
84
84
|
bool confirmed?=false
|
|
85
85
|
```
|
|
86
86
|
|
|
@@ -93,25 +93,25 @@ email contact filters=trim|lower {
|
|
|
93
93
|
|
|
94
94
|
### password
|
|
95
95
|
```xs
|
|
96
|
-
password secret filters=min:8
|
|
96
|
+
password secret filters=min:8 // Minimum 8 characters
|
|
97
97
|
```
|
|
98
98
|
|
|
99
99
|
### timestamp / date
|
|
100
100
|
```xs
|
|
101
|
-
timestamp created_at?=now
|
|
101
|
+
timestamp created_at?=now // Defaults to current time
|
|
102
102
|
date birth_date
|
|
103
103
|
```
|
|
104
104
|
|
|
105
105
|
### uuid
|
|
106
106
|
```xs
|
|
107
107
|
uuid session_id
|
|
108
|
-
uuid user_id { table = "user" }
|
|
108
|
+
uuid user_id { table = "user" } // Foreign key reference
|
|
109
109
|
```
|
|
110
110
|
|
|
111
111
|
### json
|
|
112
112
|
```xs
|
|
113
|
-
json metadata
|
|
114
|
-
json settings?={}
|
|
113
|
+
json metadata // Any JSON structure
|
|
114
|
+
json settings?={} // Default empty object
|
|
115
115
|
```
|
|
116
116
|
|
|
117
117
|
### enum
|
|
@@ -140,8 +140,8 @@ object address {
|
|
|
140
140
|
|
|
141
141
|
### Arrays
|
|
142
142
|
```xs
|
|
143
|
-
text[] tags filters=trim|lower
|
|
144
|
-
int[1:10] scores filters=min:0|max:100
|
|
143
|
+
text[] tags filters=trim|lower // Array of trimmed lowercase strings
|
|
144
|
+
int[1:10] scores filters=min:0|max:100 // 1-10 integers between 0-100
|
|
145
145
|
object[] items {
|
|
146
146
|
schema {
|
|
147
147
|
int id
|
|
@@ -212,19 +212,19 @@ input {
|
|
|
212
212
|
|
|
213
213
|
```xs
|
|
214
214
|
input {
|
|
215
|
-
|
|
215
|
+
// Required, cannot be null
|
|
216
216
|
text required_field
|
|
217
217
|
|
|
218
|
-
|
|
218
|
+
// Required, can be null (must provide, can send null)
|
|
219
219
|
text? nullable_field
|
|
220
220
|
|
|
221
|
-
|
|
221
|
+
// Optional, cannot be null (can omit, but if sent must have value)
|
|
222
222
|
text optional_field?
|
|
223
223
|
|
|
224
|
-
|
|
224
|
+
// Optional, can be null (can omit or send null)
|
|
225
225
|
text? nullable_optional?
|
|
226
226
|
|
|
227
|
-
|
|
227
|
+
// Optional with default
|
|
228
228
|
text with_default?="hello"
|
|
229
229
|
}
|
|
230
230
|
```
|
|
@@ -268,19 +268,12 @@ input {
|
|
|
268
268
|
|
|
269
269
|
## Validation with Preconditions
|
|
270
270
|
|
|
271
|
-
For complex validation beyond filters:
|
|
271
|
+
For complex validation beyond filters, use preconditions. For complete error handling reference, use `xanoscript_docs({ keyword: "syntax" })`.
|
|
272
272
|
|
|
273
273
|
```xs
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
error = "Start date must be before end date"
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
precondition ($input.password == $input.confirm_password) {
|
|
281
|
-
error_type = "inputerror"
|
|
282
|
-
error = "Passwords must match"
|
|
283
|
-
}
|
|
274
|
+
precondition ($input.start_date < $input.end_date) {
|
|
275
|
+
error_type = "inputerror"
|
|
276
|
+
error = "Start date must be before end date"
|
|
284
277
|
}
|
|
285
278
|
```
|
|
286
279
|
|
|
@@ -290,8 +283,5 @@ stack {
|
|
|
290
283
|
|
|
291
284
|
1. **Always specify types** - Never leave inputs untyped
|
|
292
285
|
2. **Use filters first** - Prefer declarative filters over stack validation
|
|
293
|
-
3. **
|
|
294
|
-
4. **
|
|
295
|
-
5. **Use defaults sparingly** - Make requirements explicit
|
|
296
|
-
6. **Validate at boundaries** - Validate user input, trust internal calls
|
|
297
|
-
7. **Limit nesting depth** - Keep object schemas 2-3 levels max
|
|
286
|
+
3. **Mark sensitive data** - Use `sensitive = true` for PII/credentials
|
|
287
|
+
4. **Validate at boundaries** - Validate user input, trust internal calls
|