@xano/developer-mcp 1.0.20 → 1.0.22
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 +100 -19
- package/dist/index.js +4 -227
- package/dist/meta_api_docs/format.d.ts +16 -1
- package/dist/meta_api_docs/format.js +24 -6
- package/dist/meta_api_docs/format.test.d.ts +1 -0
- package/dist/meta_api_docs/format.test.js +274 -0
- package/dist/meta_api_docs/index.test.d.ts +1 -0
- package/dist/meta_api_docs/index.test.js +128 -0
- package/dist/meta_api_docs/types.test.d.ts +1 -0
- package/dist/meta_api_docs/types.test.js +132 -0
- package/dist/run_api_docs/format.d.ts +1 -0
- package/dist/run_api_docs/format.js +3 -170
- package/dist/run_api_docs/format.test.d.ts +1 -0
- package/dist/run_api_docs/format.test.js +86 -0
- package/dist/run_api_docs/index.test.d.ts +1 -0
- package/dist/run_api_docs/index.test.js +127 -0
- package/dist/templates/init-workspace.js +4 -4
- package/dist/templates/xanoscript-index.d.ts +3 -1
- package/dist/templates/xanoscript-index.js +54 -51
- package/dist/xanoscript.d.ts +41 -0
- package/dist/xanoscript.js +261 -0
- package/dist/xanoscript.test.d.ts +1 -0
- package/dist/xanoscript.test.js +303 -0
- package/dist/xanoscript_docs/README.md +53 -37
- package/dist/xanoscript_docs/agents.md +1 -1
- package/dist/xanoscript_docs/apis.md +6 -3
- package/dist/xanoscript_docs/branch.md +239 -0
- package/dist/xanoscript_docs/functions.md +6 -6
- package/dist/xanoscript_docs/integrations.md +43 -1
- package/dist/xanoscript_docs/middleware.md +321 -0
- package/dist/xanoscript_docs/performance.md +1 -1
- package/dist/xanoscript_docs/realtime.md +113 -1
- package/dist/xanoscript_docs/tasks.md +2 -2
- package/dist/xanoscript_docs/tools.md +3 -3
- package/dist/xanoscript_docs/types.md +25 -8
- package/dist/xanoscript_docs/workspace.md +209 -0
- package/dist/xanoscript_docs_auto/README.md +119 -0
- package/dist/xanoscript_docs_auto/agents.md +446 -0
- package/dist/xanoscript_docs_auto/apis.md +517 -0
- package/dist/xanoscript_docs_auto/control-flow.md +543 -0
- package/dist/xanoscript_docs_auto/database.md +551 -0
- package/dist/xanoscript_docs_auto/debugging.md +527 -0
- package/dist/xanoscript_docs_auto/filters.md +464 -0
- package/dist/xanoscript_docs_auto/functions.md +431 -0
- package/dist/xanoscript_docs_auto/integrations.md +657 -0
- package/dist/xanoscript_docs_auto/mcp-servers.md +408 -0
- package/dist/xanoscript_docs_auto/operators.md +368 -0
- package/dist/xanoscript_docs_auto/syntax.md +287 -0
- package/dist/xanoscript_docs_auto/tables.md +447 -0
- package/dist/xanoscript_docs_auto/tasks.md +479 -0
- package/dist/xanoscript_docs_auto/testing.md +574 -0
- package/dist/xanoscript_docs_auto/tools.md +485 -0
- package/dist/xanoscript_docs_auto/triggers.md +595 -0
- package/dist/xanoscript_docs_auto/types.md +323 -0
- package/dist/xanoscript_docs_auto/variables.md +462 -0
- package/dist/xanoscript_docs_auto/version.json +5 -0
- package/package.json +6 -2
|
@@ -0,0 +1,543 @@
|
|
|
1
|
+
---
|
|
2
|
+
applyTo: "**/*.xs"
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Control Flow
|
|
6
|
+
|
|
7
|
+
Conditionals, loops, and error handling in XanoScript.
|
|
8
|
+
|
|
9
|
+
## Quick Reference
|
|
10
|
+
|
|
11
|
+
| Structure | Purpose |
|
|
12
|
+
|-----------|---------|
|
|
13
|
+
| `conditional` | If/elseif/else branching |
|
|
14
|
+
| `switch` | Multi-case matching |
|
|
15
|
+
| `for` | Fixed iteration count |
|
|
16
|
+
| `foreach` | Array iteration |
|
|
17
|
+
| `while` | Condition-based loop |
|
|
18
|
+
| `try_catch` | Error handling |
|
|
19
|
+
| `precondition` | Validation with typed errors |
|
|
20
|
+
| `break` | Exit loop |
|
|
21
|
+
| `continue` | Skip to next iteration |
|
|
22
|
+
| `return` | Exit function with value |
|
|
23
|
+
| `throw` | Raise error |
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Conditional (if/elseif/else)
|
|
28
|
+
|
|
29
|
+
### Basic If
|
|
30
|
+
|
|
31
|
+
```xs
|
|
32
|
+
conditional {
|
|
33
|
+
if ($input.age >= 18) {
|
|
34
|
+
var $status { value = "adult" }
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### If/Else
|
|
40
|
+
|
|
41
|
+
```xs
|
|
42
|
+
conditional {
|
|
43
|
+
if ($user != null) {
|
|
44
|
+
var $message { value = "Welcome, " ~ $user.name }
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
var $message { value = "Please log in" }
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### If/Elseif/Else
|
|
53
|
+
|
|
54
|
+
```xs
|
|
55
|
+
conditional {
|
|
56
|
+
if ($input.score >= 90) {
|
|
57
|
+
var $grade { value = "A" }
|
|
58
|
+
}
|
|
59
|
+
elseif ($input.score >= 80) {
|
|
60
|
+
var $grade { value = "B" }
|
|
61
|
+
}
|
|
62
|
+
elseif ($input.score >= 70) {
|
|
63
|
+
var $grade { value = "C" }
|
|
64
|
+
}
|
|
65
|
+
elseif ($input.score >= 60) {
|
|
66
|
+
var $grade { value = "D" }
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
var $grade { value = "F" }
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Nested Conditionals
|
|
75
|
+
|
|
76
|
+
```xs
|
|
77
|
+
conditional {
|
|
78
|
+
if ($user != null) {
|
|
79
|
+
conditional {
|
|
80
|
+
if ($user.role == "admin") {
|
|
81
|
+
var $access { value = "full" }
|
|
82
|
+
}
|
|
83
|
+
elseif ($user.role == "moderator") {
|
|
84
|
+
var $access { value = "partial" }
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
var $access { value = "basic" }
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
var $access { value = "none" }
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Switch Statement
|
|
100
|
+
|
|
101
|
+
Match against multiple cases:
|
|
102
|
+
|
|
103
|
+
```xs
|
|
104
|
+
switch ($input.status) {
|
|
105
|
+
case ("pending") {
|
|
106
|
+
var $action { value = "review" }
|
|
107
|
+
} break
|
|
108
|
+
case ("approved") {
|
|
109
|
+
var $action { value = "process" }
|
|
110
|
+
} break
|
|
111
|
+
case ("rejected") {
|
|
112
|
+
var $action { value = "notify" }
|
|
113
|
+
} break
|
|
114
|
+
default {
|
|
115
|
+
var $action { value = "unknown" }
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Multiple Values per Case
|
|
121
|
+
|
|
122
|
+
```xs
|
|
123
|
+
switch ($input.method) {
|
|
124
|
+
case ("GET", "HEAD") {
|
|
125
|
+
var $type { value = "read" }
|
|
126
|
+
} break
|
|
127
|
+
case ("POST", "PUT", "PATCH") {
|
|
128
|
+
var $type { value = "write" }
|
|
129
|
+
} break
|
|
130
|
+
case ("DELETE") {
|
|
131
|
+
var $type { value = "delete" }
|
|
132
|
+
} break
|
|
133
|
+
default {
|
|
134
|
+
var $type { value = "other" }
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## For Loop
|
|
142
|
+
|
|
143
|
+
Fixed number of iterations:
|
|
144
|
+
|
|
145
|
+
```xs
|
|
146
|
+
for (10) {
|
|
147
|
+
each as $index {
|
|
148
|
+
debug.log { value = "Iteration: " ~ $index }
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### With Variable Count
|
|
154
|
+
|
|
155
|
+
```xs
|
|
156
|
+
for ($input.count) {
|
|
157
|
+
each as $i {
|
|
158
|
+
array.push {
|
|
159
|
+
array = $items
|
|
160
|
+
value = {index: $i}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Building Arrays
|
|
167
|
+
|
|
168
|
+
```xs
|
|
169
|
+
var $squares { value = [] }
|
|
170
|
+
|
|
171
|
+
for (5) {
|
|
172
|
+
each as $n {
|
|
173
|
+
var $square { value = ($n + 1) * ($n + 1) }
|
|
174
|
+
array.push {
|
|
175
|
+
array = $squares
|
|
176
|
+
value = $square
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
// $squares = [1, 4, 9, 16, 25]
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## Foreach Loop
|
|
186
|
+
|
|
187
|
+
Iterate over arrays:
|
|
188
|
+
|
|
189
|
+
```xs
|
|
190
|
+
foreach ($input.items) {
|
|
191
|
+
each as $item {
|
|
192
|
+
debug.log { value = $item }
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### With Index
|
|
198
|
+
|
|
199
|
+
```xs
|
|
200
|
+
foreach ($input.users) {
|
|
201
|
+
each as $user {
|
|
202
|
+
debug.log {
|
|
203
|
+
value = "User " ~ $this.index ~ ": " ~ $user.name
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Processing Array Elements
|
|
210
|
+
|
|
211
|
+
```xs
|
|
212
|
+
var $processed { value = [] }
|
|
213
|
+
|
|
214
|
+
foreach ($input.orders) {
|
|
215
|
+
each as $order {
|
|
216
|
+
function.run "calculate_total" {
|
|
217
|
+
input = {order: $order}
|
|
218
|
+
} as $total
|
|
219
|
+
|
|
220
|
+
array.push {
|
|
221
|
+
array = $processed
|
|
222
|
+
value = {
|
|
223
|
+
id: $order.id,
|
|
224
|
+
total: $total
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## While Loop
|
|
234
|
+
|
|
235
|
+
Repeat while condition is true:
|
|
236
|
+
|
|
237
|
+
```xs
|
|
238
|
+
var $counter { value = 0 }
|
|
239
|
+
|
|
240
|
+
while ($counter < 10) {
|
|
241
|
+
each {
|
|
242
|
+
debug.log { value = $counter }
|
|
243
|
+
var.update $counter { value = $counter + 1 }
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### Pagination Example
|
|
249
|
+
|
|
250
|
+
```xs
|
|
251
|
+
var $page { value = 1 }
|
|
252
|
+
var $has_more { value = true }
|
|
253
|
+
var $all_items { value = [] }
|
|
254
|
+
|
|
255
|
+
while ($has_more) {
|
|
256
|
+
each {
|
|
257
|
+
api.request {
|
|
258
|
+
url = "https://api.example.com/items"
|
|
259
|
+
params = {page: $page, limit: 100}
|
|
260
|
+
} as $response
|
|
261
|
+
|
|
262
|
+
array.merge {
|
|
263
|
+
array = $all_items
|
|
264
|
+
with = $response.data
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
var.update $has_more {
|
|
268
|
+
value = $response.data|count == 100
|
|
269
|
+
}
|
|
270
|
+
var.update $page { value = $page + 1 }
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
## Loop Control
|
|
278
|
+
|
|
279
|
+
### Break
|
|
280
|
+
|
|
281
|
+
Exit the loop immediately:
|
|
282
|
+
|
|
283
|
+
```xs
|
|
284
|
+
foreach ($input.items) {
|
|
285
|
+
each as $item {
|
|
286
|
+
conditional {
|
|
287
|
+
if ($item.id == $input.target_id) {
|
|
288
|
+
var $found { value = $item }
|
|
289
|
+
break
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### Continue
|
|
297
|
+
|
|
298
|
+
Skip to next iteration:
|
|
299
|
+
|
|
300
|
+
```xs
|
|
301
|
+
foreach ($input.users) {
|
|
302
|
+
each as $user {
|
|
303
|
+
conditional {
|
|
304
|
+
if (!$user.active) {
|
|
305
|
+
continue
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Only runs for active users
|
|
310
|
+
function.run "process_user" {
|
|
311
|
+
input = {user: $user}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
---
|
|
318
|
+
|
|
319
|
+
## Try/Catch/Finally
|
|
320
|
+
|
|
321
|
+
Handle errors gracefully:
|
|
322
|
+
|
|
323
|
+
```xs
|
|
324
|
+
try_catch {
|
|
325
|
+
try {
|
|
326
|
+
function.run "risky_operation" {
|
|
327
|
+
input = {data: $input.data}
|
|
328
|
+
} as $result
|
|
329
|
+
}
|
|
330
|
+
catch {
|
|
331
|
+
debug.log { value = "Error: " ~ $error.message }
|
|
332
|
+
var $result { value = null }
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
### With Finally
|
|
338
|
+
|
|
339
|
+
```xs
|
|
340
|
+
try_catch {
|
|
341
|
+
try {
|
|
342
|
+
db.add user {
|
|
343
|
+
data = $input.user_data
|
|
344
|
+
} as $user
|
|
345
|
+
}
|
|
346
|
+
catch {
|
|
347
|
+
debug.log { value = "Failed to create user" }
|
|
348
|
+
throw {
|
|
349
|
+
name = "CreateError"
|
|
350
|
+
value = $error.message
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
finally {
|
|
354
|
+
debug.log { value = "Operation completed" }
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
### Accessing Error Info
|
|
360
|
+
|
|
361
|
+
In catch blocks, `$error` contains:
|
|
362
|
+
|
|
363
|
+
```xs
|
|
364
|
+
catch {
|
|
365
|
+
var $error_name { value = $error.name }
|
|
366
|
+
var $error_message { value = $error.message }
|
|
367
|
+
var $error_code { value = $error.code }
|
|
368
|
+
}
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
---
|
|
372
|
+
|
|
373
|
+
## Preconditions
|
|
374
|
+
|
|
375
|
+
Validate conditions and throw typed errors:
|
|
376
|
+
|
|
377
|
+
```xs
|
|
378
|
+
precondition ($input.amount > 0) {
|
|
379
|
+
error_type = "inputerror"
|
|
380
|
+
error = "Amount must be positive"
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
precondition ($user != null) {
|
|
384
|
+
error_type = "notfound"
|
|
385
|
+
error = "User not found"
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
precondition ($user.id == $auth.id) {
|
|
389
|
+
error_type = "accessdenied"
|
|
390
|
+
error = "Not authorized"
|
|
391
|
+
}
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
### Error Types
|
|
395
|
+
|
|
396
|
+
| Type | HTTP Status | Use Case |
|
|
397
|
+
|------|-------------|----------|
|
|
398
|
+
| `inputerror` | 400 Bad Request | Invalid input data |
|
|
399
|
+
| `accessdenied` | 403 Forbidden | Authorization failure |
|
|
400
|
+
| `notfound` | 404 Not Found | Resource doesn't exist |
|
|
401
|
+
| `standard` | 500 Internal Server Error | General errors |
|
|
402
|
+
|
|
403
|
+
---
|
|
404
|
+
|
|
405
|
+
## Throw
|
|
406
|
+
|
|
407
|
+
Raise custom errors:
|
|
408
|
+
|
|
409
|
+
```xs
|
|
410
|
+
throw {
|
|
411
|
+
name = "ValidationError"
|
|
412
|
+
value = "Email format is invalid"
|
|
413
|
+
}
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
### With Error Code
|
|
417
|
+
|
|
418
|
+
```xs
|
|
419
|
+
throw {
|
|
420
|
+
name = "APIError"
|
|
421
|
+
value = "Rate limit exceeded"
|
|
422
|
+
code = 429
|
|
423
|
+
}
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
---
|
|
427
|
+
|
|
428
|
+
## Return
|
|
429
|
+
|
|
430
|
+
Exit function early with a value:
|
|
431
|
+
|
|
432
|
+
```xs
|
|
433
|
+
conditional {
|
|
434
|
+
if ($input.skip) {
|
|
435
|
+
return { value = null }
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// Only reached if not skipping
|
|
440
|
+
db.query user {} as $users
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
### Return from Nested Logic
|
|
444
|
+
|
|
445
|
+
```xs
|
|
446
|
+
conditional {
|
|
447
|
+
if ($cached != null) {
|
|
448
|
+
return { value = $cached }
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// Cache miss - fetch from database
|
|
453
|
+
db.get user {
|
|
454
|
+
field_name = "id"
|
|
455
|
+
field_value = $input.id
|
|
456
|
+
} as $user
|
|
457
|
+
|
|
458
|
+
return { value = $user }
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
---
|
|
462
|
+
|
|
463
|
+
## Pattern: Guard Clauses
|
|
464
|
+
|
|
465
|
+
Use early returns to simplify logic:
|
|
466
|
+
|
|
467
|
+
```xs
|
|
468
|
+
function "process_order" {
|
|
469
|
+
input { int order_id }
|
|
470
|
+
stack {
|
|
471
|
+
// Guard: Check order exists
|
|
472
|
+
db.get order {
|
|
473
|
+
field_name = "id"
|
|
474
|
+
field_value = $input.order_id
|
|
475
|
+
} as $order
|
|
476
|
+
|
|
477
|
+
precondition ($order != null) {
|
|
478
|
+
error_type = "notfound"
|
|
479
|
+
error = "Order not found"
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// Guard: Check order is processable
|
|
483
|
+
precondition ($order.status == "pending") {
|
|
484
|
+
error_type = "inputerror"
|
|
485
|
+
error = "Order already processed"
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
// Guard: Check user is authorized
|
|
489
|
+
precondition ($order.user_id == $auth.id || $auth.role == "admin") {
|
|
490
|
+
error_type = "accessdenied"
|
|
491
|
+
error = "Not authorized to process this order"
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// Main logic (only reached if all guards pass)
|
|
495
|
+
db.edit order {
|
|
496
|
+
field_name = "id"
|
|
497
|
+
field_value = $order.id
|
|
498
|
+
data = {status: "processing"}
|
|
499
|
+
} as $updated
|
|
500
|
+
}
|
|
501
|
+
response = $updated
|
|
502
|
+
}
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
---
|
|
506
|
+
|
|
507
|
+
## Pattern: Retry Logic
|
|
508
|
+
|
|
509
|
+
```xs
|
|
510
|
+
var $attempts { value = 0 }
|
|
511
|
+
var $max_attempts { value = 3 }
|
|
512
|
+
var $success { value = false }
|
|
513
|
+
|
|
514
|
+
while (!$success && $attempts < $max_attempts) {
|
|
515
|
+
each {
|
|
516
|
+
var.update $attempts { value = $attempts + 1 }
|
|
517
|
+
|
|
518
|
+
try_catch {
|
|
519
|
+
try {
|
|
520
|
+
api.request {
|
|
521
|
+
url = $external_api_url
|
|
522
|
+
method = "POST"
|
|
523
|
+
body = $payload
|
|
524
|
+
} as $response
|
|
525
|
+
|
|
526
|
+
var.update $success { value = true }
|
|
527
|
+
}
|
|
528
|
+
catch {
|
|
529
|
+
conditional {
|
|
530
|
+
if ($attempts < $max_attempts) {
|
|
531
|
+
util.sleep { duration = 1000 * $attempts }
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
precondition ($success) {
|
|
540
|
+
error_type = "standard"
|
|
541
|
+
error = "Failed after " ~ $max_attempts ~ " attempts"
|
|
542
|
+
}
|
|
543
|
+
```
|