@xano/developer-mcp 1.0.6 → 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/package.json +1 -1
- package/xanoscript_docs/README.md +34 -24
- package/xanoscript_docs/agents.md +12 -12
- package/xanoscript_docs/apis.md +14 -14
- package/xanoscript_docs/database.md +27 -27
- package/xanoscript_docs/ephemeral.md +2 -2
- package/xanoscript_docs/frontend.md +2 -2
- package/xanoscript_docs/functions.md +8 -8
- package/xanoscript_docs/integrations.md +5 -5
- package/xanoscript_docs/mcp-servers.md +7 -7
- package/xanoscript_docs/syntax.md +48 -48
- package/xanoscript_docs/tables.md +7 -7
- package/xanoscript_docs/tasks.md +1 -1
- package/xanoscript_docs/triggers.md +10 -10
- package/xanoscript_docs/types.md +15 -15
package/package.json
CHANGED
|
@@ -16,22 +16,24 @@ XanoScript is the declarative scripting language for [Xano](https://xano.com), a
|
|
|
16
16
|
| `mcp_server` | `mcp_servers/**/*.xs` | MCP server definitions |
|
|
17
17
|
| `addon` | `addons/*.xs` | Subqueries for related data |
|
|
18
18
|
|
|
19
|
+
**Important:** Each `.xs` file must contain exactly one definition. You cannot define multiple tables, functions, queries, or other constructs in a single file.
|
|
20
|
+
|
|
19
21
|
## Workspace Structure
|
|
20
22
|
|
|
21
23
|
```
|
|
22
24
|
project/
|
|
23
|
-
├── tables/
|
|
24
|
-
├── functions/
|
|
25
|
+
├── tables/ // Database table schemas
|
|
26
|
+
├── functions/ // Reusable functions (supports subfolders)
|
|
25
27
|
├── apis/
|
|
26
|
-
│ └── <api-group>/
|
|
27
|
-
├── tasks/
|
|
28
|
-
├── triggers/
|
|
29
|
-
├── agents/
|
|
30
|
-
├── tools/
|
|
31
|
-
├── mcp_servers/
|
|
32
|
-
├── addons/
|
|
33
|
-
├── static/
|
|
34
|
-
└── ephemeral/
|
|
28
|
+
│ └── <api-group>/ // API endpoints grouped by domain
|
|
29
|
+
├── tasks/ // Scheduled jobs
|
|
30
|
+
├── triggers/ // Event-driven handlers
|
|
31
|
+
├── agents/ // AI agents
|
|
32
|
+
├── tools/ // AI tools
|
|
33
|
+
├── mcp_servers/ // MCP server definitions
|
|
34
|
+
├── addons/ // Query addons
|
|
35
|
+
├── static/ // Frontend files (HTML, CSS, JS)
|
|
36
|
+
└── ephemeral/ // Temporary test environments
|
|
35
37
|
```
|
|
36
38
|
|
|
37
39
|
## Environment Variables
|
|
@@ -55,28 +57,36 @@ Custom environment variables are set in the Xano dashboard and accessed as `$env
|
|
|
55
57
|
### Block Structure
|
|
56
58
|
```xs
|
|
57
59
|
<construct> "<name>" {
|
|
58
|
-
input { ... }
|
|
59
|
-
stack { ... }
|
|
60
|
-
response = $var
|
|
60
|
+
input { ... } // Parameters (optional)
|
|
61
|
+
stack { ... } // Logic
|
|
62
|
+
response = $var // Output
|
|
61
63
|
}
|
|
62
64
|
```
|
|
63
65
|
|
|
64
66
|
### Variable Access
|
|
65
67
|
```xs
|
|
66
|
-
$input.field
|
|
67
|
-
$var.field
|
|
68
|
-
$auth.id
|
|
69
|
-
$env.MY_VAR
|
|
70
|
-
$db.table.field
|
|
71
|
-
$this
|
|
68
|
+
$input.field // Input parameters
|
|
69
|
+
$var.field // Stack variables
|
|
70
|
+
$auth.id // Authenticated user ID
|
|
71
|
+
$env.MY_VAR // Environment variable
|
|
72
|
+
$db.table.field // Database field reference (in queries)
|
|
73
|
+
$this // Current item in loops/maps
|
|
72
74
|
```
|
|
73
75
|
|
|
76
|
+
### Comments
|
|
77
|
+
```xs
|
|
78
|
+
// Single-line comment
|
|
79
|
+
var $total { value = 0 } // Inline comment
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**Note:** XanoScript only supports `//` for comments. Other comment styles like `#` are not supported.
|
|
83
|
+
|
|
74
84
|
### Filters (Pipe Syntax)
|
|
75
85
|
```xs
|
|
76
|
-
$value|trim|lower
|
|
77
|
-
$input.name|strlen
|
|
78
|
-
$array|first
|
|
79
|
-
($a + $b)|round:2
|
|
86
|
+
$value|trim|lower // Chain filters
|
|
87
|
+
$input.name|strlen // Get length
|
|
88
|
+
$array|first // First element
|
|
89
|
+
($a + $b)|round:2 // Math with precision
|
|
80
90
|
```
|
|
81
91
|
|
|
82
92
|
## File Frontmatter
|
|
@@ -71,10 +71,10 @@ ai.agent.run "Customer Support" {
|
|
|
71
71
|
|
|
72
72
|
```xs
|
|
73
73
|
llm = {
|
|
74
|
-
type: "<provider>"
|
|
75
|
-
system_prompt: "..."
|
|
76
|
-
prompt: "{{ $args.input }}"
|
|
77
|
-
max_steps: 5
|
|
74
|
+
type: "<provider>" // Required
|
|
75
|
+
system_prompt: "..." // Agent persona and rules
|
|
76
|
+
prompt: "{{ $args.input }}" // User input template
|
|
77
|
+
max_steps: 5 // Max LLM calls per run
|
|
78
78
|
}
|
|
79
79
|
```
|
|
80
80
|
|
|
@@ -94,7 +94,7 @@ llm = {
|
|
|
94
94
|
prompt: "{{ $args.message }}"
|
|
95
95
|
max_steps: 3
|
|
96
96
|
temperature: 0
|
|
97
|
-
search_grounding: false
|
|
97
|
+
search_grounding: false // Google Search grounding
|
|
98
98
|
}
|
|
99
99
|
```
|
|
100
100
|
|
|
@@ -108,7 +108,7 @@ llm = {
|
|
|
108
108
|
prompt: "{{ $args.message }}"
|
|
109
109
|
max_steps: 5
|
|
110
110
|
temperature: 0.2
|
|
111
|
-
thinking_tokens: 10000
|
|
111
|
+
thinking_tokens: 10000 // Extended thinking
|
|
112
112
|
include_thoughts: true
|
|
113
113
|
}
|
|
114
114
|
```
|
|
@@ -123,7 +123,7 @@ llm = {
|
|
|
123
123
|
prompt: "{{ $args.message }}"
|
|
124
124
|
max_steps: 5
|
|
125
125
|
temperature: 0.8
|
|
126
|
-
reasoning_effort: "medium"
|
|
126
|
+
reasoning_effort: "medium" // low, medium, high
|
|
127
127
|
}
|
|
128
128
|
```
|
|
129
129
|
|
|
@@ -134,7 +134,7 @@ llm = {
|
|
|
134
134
|
api_key: "{{ $env.GROQ_API_KEY }}"
|
|
135
135
|
baseURL: "https://api.groq.com/openai/v1"
|
|
136
136
|
model: "llama-3.3-70b-versatile"
|
|
137
|
-
compatibility: "compatible"
|
|
137
|
+
compatibility: "compatible" // Required for non-OpenAI
|
|
138
138
|
...
|
|
139
139
|
}
|
|
140
140
|
```
|
|
@@ -151,7 +151,7 @@ llm = {
|
|
|
151
151
|
prompt: "{{ $args.message }}"
|
|
152
152
|
max_steps: 8
|
|
153
153
|
temperature: 0.3
|
|
154
|
-
send_reasoning: true
|
|
154
|
+
send_reasoning: true // Include thinking blocks
|
|
155
155
|
}
|
|
156
156
|
```
|
|
157
157
|
|
|
@@ -218,9 +218,9 @@ llm = {
|
|
|
218
218
|
|
|
219
219
|
### Available Variables
|
|
220
220
|
```xs
|
|
221
|
-
{{ $args.any_arg }}
|
|
222
|
-
{{ $env.MY_VAR }}
|
|
223
|
-
{{ "now"|date("Y-m-d") }}
|
|
221
|
+
{{ $args.any_arg }} // Runtime arguments
|
|
222
|
+
{{ $env.MY_VAR }} // Environment variables
|
|
223
|
+
{{ "now"|date("Y-m-d") }} // Current date
|
|
224
224
|
```
|
|
225
225
|
|
|
226
226
|
---
|
package/xanoscript_docs/apis.md
CHANGED
|
@@ -9,19 +9,19 @@ HTTP endpoint definitions in XanoScript.
|
|
|
9
9
|
## Quick Reference
|
|
10
10
|
|
|
11
11
|
```xs
|
|
12
|
-
query "
|
|
13
|
-
api_group = "<GroupName>"
|
|
12
|
+
query "endpoint-path" verb=<METHOD> {
|
|
13
|
+
api_group = "<GroupName>" // Required: API group for organization
|
|
14
14
|
description = "What this endpoint does"
|
|
15
|
-
auth = "<table>"
|
|
15
|
+
auth = "<table>" // Optional: require authentication
|
|
16
16
|
input { ... }
|
|
17
17
|
stack { ... }
|
|
18
18
|
response = $result
|
|
19
19
|
}
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
### Query Name (Required)
|
|
22
|
+
### Query Name (Required, Non-Empty)
|
|
23
23
|
|
|
24
|
-
The query name is **required** and
|
|
24
|
+
The query name is **required** and **must be a non-empty string**. Empty names (`query "" verb=...`) are invalid. The name defines the endpoint path after the API group canonical.
|
|
25
25
|
|
|
26
26
|
**Full URL path structure:**
|
|
27
27
|
```
|
|
@@ -42,8 +42,8 @@ Every endpoint must belong to an API group. Each group is a folder with an `api_
|
|
|
42
42
|
|
|
43
43
|
```xs
|
|
44
44
|
api_group "users" {
|
|
45
|
-
canonical = "users"
|
|
46
|
-
description = "User management"
|
|
45
|
+
canonical = "users" // Required: URL path segment
|
|
46
|
+
description = "User management" // Optional
|
|
47
47
|
}
|
|
48
48
|
```
|
|
49
49
|
|
|
@@ -51,12 +51,12 @@ api_group "users" {
|
|
|
51
51
|
```
|
|
52
52
|
apis/
|
|
53
53
|
├── users/
|
|
54
|
-
│ ├── api_group.xs
|
|
55
|
-
│ ├── list.xs
|
|
56
|
-
│ └── by-id.xs
|
|
54
|
+
│ ├── api_group.xs // Defines group (canonical = "users")
|
|
55
|
+
│ ├── list.xs // GET /users/list
|
|
56
|
+
│ └── by-id.xs // GET/PATCH/DELETE /users/{id}
|
|
57
57
|
└── products/
|
|
58
|
-
├── api_group.xs
|
|
59
|
-
└── search.xs
|
|
58
|
+
├── api_group.xs // Defines group (canonical = "products")
|
|
59
|
+
└── search.xs // GET /products/search
|
|
60
60
|
```
|
|
61
61
|
|
|
62
62
|
Full URL: `/<canonical>/<query name>` (e.g., `/users/profile`)
|
|
@@ -99,11 +99,11 @@ query "status" verb=GET {
|
|
|
99
99
|
```xs
|
|
100
100
|
query "profile" verb=GET {
|
|
101
101
|
api_group = "Users"
|
|
102
|
-
auth = "user"
|
|
102
|
+
auth = "user" // Requires valid JWT
|
|
103
103
|
stack {
|
|
104
104
|
db.get "user" {
|
|
105
105
|
field_name = "id"
|
|
106
|
-
field_value = $auth.id
|
|
106
|
+
field_value = $auth.id // User ID from token
|
|
107
107
|
} as $user
|
|
108
108
|
}
|
|
109
109
|
response = $user
|
|
@@ -35,7 +35,7 @@ db.query "product" {
|
|
|
35
35
|
|
|
36
36
|
### Where Operators
|
|
37
37
|
```xs
|
|
38
|
-
|
|
38
|
+
// Comparison
|
|
39
39
|
$db.product.price == 100
|
|
40
40
|
$db.product.price != 0
|
|
41
41
|
$db.product.price > 50
|
|
@@ -43,32 +43,32 @@ $db.product.price >= 50
|
|
|
43
43
|
$db.product.price < 100
|
|
44
44
|
$db.product.price <= 100
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
// Null-safe (ignore if value is null)
|
|
47
47
|
$db.product.category ==? $input.category
|
|
48
48
|
$db.product.price >=? $input.min_price
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
$db.product.name includes "phone"
|
|
52
|
-
$db.product.tags contains "featured"
|
|
50
|
+
// String matching
|
|
51
|
+
$db.product.name includes "phone" // Contains substring
|
|
52
|
+
$db.product.tags contains "featured" // Array contains value
|
|
53
53
|
$db.product.tags not contains "hidden"
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
// Array overlap
|
|
56
56
|
$db.product.tags overlaps ["a", "b"]
|
|
57
57
|
$db.product.tags not overlaps ["x", "y"]
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
// Combining conditions
|
|
60
60
|
$db.product.is_active == true && $db.product.price > 0
|
|
61
61
|
$db.product.category == "electronics" || $db.product.featured == true
|
|
62
62
|
```
|
|
63
63
|
|
|
64
64
|
### Return Types
|
|
65
65
|
```xs
|
|
66
|
-
|
|
66
|
+
// List (default)
|
|
67
67
|
db.query "product" {
|
|
68
68
|
return = { type: "list" }
|
|
69
69
|
} as $products
|
|
70
70
|
|
|
71
|
-
|
|
71
|
+
// With pagination
|
|
72
72
|
db.query "product" {
|
|
73
73
|
return = {
|
|
74
74
|
type: "list",
|
|
@@ -76,19 +76,19 @@ db.query "product" {
|
|
|
76
76
|
}
|
|
77
77
|
} as $products
|
|
78
78
|
|
|
79
|
-
|
|
79
|
+
// Single record
|
|
80
80
|
db.query "product" {
|
|
81
81
|
where = $db.product.sku == $input.sku
|
|
82
82
|
return = { type: "single" }
|
|
83
83
|
} as $product
|
|
84
84
|
|
|
85
|
-
|
|
85
|
+
// Count
|
|
86
86
|
db.query "product" {
|
|
87
87
|
where = $db.product.is_active == true
|
|
88
88
|
return = { type: "count" }
|
|
89
89
|
} as $count
|
|
90
90
|
|
|
91
|
-
|
|
91
|
+
// Exists
|
|
92
92
|
db.query "product" {
|
|
93
93
|
where = $db.product.email == $input.email
|
|
94
94
|
return = { type: "exists" }
|
|
@@ -98,9 +98,9 @@ db.query "product" {
|
|
|
98
98
|
### Sorting
|
|
99
99
|
```xs
|
|
100
100
|
db.query "product" {
|
|
101
|
-
sort = { created_at: "desc" }
|
|
102
|
-
sort = { name: "asc" }
|
|
103
|
-
sort = { id: "rand" }
|
|
101
|
+
sort = { created_at: "desc" } // Descending
|
|
102
|
+
sort = { name: "asc" } // Ascending
|
|
103
|
+
sort = { id: "rand" } // Random
|
|
104
104
|
} as $products
|
|
105
105
|
```
|
|
106
106
|
|
|
@@ -110,7 +110,7 @@ db.query "comment" {
|
|
|
110
110
|
join = {
|
|
111
111
|
post: {
|
|
112
112
|
table: "post",
|
|
113
|
-
type: "inner",
|
|
113
|
+
type: "inner", // inner, left, right
|
|
114
114
|
where: $db.comment.post_id == $db.post.id
|
|
115
115
|
}
|
|
116
116
|
}
|
|
@@ -279,7 +279,7 @@ Delete all records from a table.
|
|
|
279
279
|
|
|
280
280
|
```xs
|
|
281
281
|
db.truncate "temp_data" {
|
|
282
|
-
reset = true
|
|
282
|
+
reset = true // Reset auto-increment
|
|
283
283
|
}
|
|
284
284
|
```
|
|
285
285
|
|
|
@@ -293,7 +293,7 @@ Execute raw SQL (use sparingly).
|
|
|
293
293
|
db.direct_query {
|
|
294
294
|
sql = "SELECT * FROM users WHERE email = ? AND status = ?"
|
|
295
295
|
arg = [$input.email, "active"]
|
|
296
|
-
response_type = "list"
|
|
296
|
+
response_type = "list" // list or single
|
|
297
297
|
} as $results
|
|
298
298
|
```
|
|
299
299
|
|
|
@@ -339,9 +339,9 @@ Filters for use in `where` clauses:
|
|
|
339
339
|
|
|
340
340
|
### String/Text
|
|
341
341
|
```xs
|
|
342
|
-
$db.name|to_lower
|
|
343
|
-
$db.name|concat:" "
|
|
344
|
-
$db.text|substr:0:100
|
|
342
|
+
$db.name|to_lower // Case conversion
|
|
343
|
+
$db.name|concat:" " // Concatenation
|
|
344
|
+
$db.text|substr:0:100 // Substring
|
|
345
345
|
```
|
|
346
346
|
|
|
347
347
|
### Numeric
|
|
@@ -363,8 +363,8 @@ $db.created_at|timestamp_subtract_hours:24
|
|
|
363
363
|
|
|
364
364
|
### Geographic
|
|
365
365
|
```xs
|
|
366
|
-
$db.location|distance:$input.point
|
|
367
|
-
$db.location|within:$input.point:1000
|
|
366
|
+
$db.location|distance:$input.point // Distance in meters
|
|
367
|
+
$db.location|within:$input.point:1000 // Within radius
|
|
368
368
|
```
|
|
369
369
|
|
|
370
370
|
### Vector (AI/ML)
|
|
@@ -385,7 +385,7 @@ $db.content|search_rank:$input.query
|
|
|
385
385
|
Connect to external databases:
|
|
386
386
|
|
|
387
387
|
```xs
|
|
388
|
-
|
|
388
|
+
// PostgreSQL
|
|
389
389
|
db.external.postgres.direct_query {
|
|
390
390
|
connection_string = $env.EXTERNAL_PG_URL
|
|
391
391
|
sql = "SELECT * FROM users WHERE id = ?"
|
|
@@ -393,13 +393,13 @@ db.external.postgres.direct_query {
|
|
|
393
393
|
response_type = "single"
|
|
394
394
|
} as $user
|
|
395
395
|
|
|
396
|
-
|
|
396
|
+
// MySQL
|
|
397
397
|
db.external.mysql.direct_query { ... }
|
|
398
398
|
|
|
399
|
-
|
|
399
|
+
// MS SQL
|
|
400
400
|
db.external.mssql.direct_query { ... }
|
|
401
401
|
|
|
402
|
-
|
|
402
|
+
// Oracle
|
|
403
403
|
db.external.oracle.direct_query { ... }
|
|
404
404
|
```
|
|
405
405
|
|
|
@@ -116,8 +116,8 @@ One-time operation with setup and cleanup hooks.
|
|
|
116
116
|
```xs
|
|
117
117
|
function "$main" {
|
|
118
118
|
input {
|
|
119
|
-
json args
|
|
120
|
-
json pre
|
|
119
|
+
json args // Runtime arguments
|
|
120
|
+
json pre // Result from $pre
|
|
121
121
|
}
|
|
122
122
|
stack {
|
|
123
123
|
db.query authors {
|
|
@@ -11,10 +11,10 @@ Static frontend development and Lovable/Supabase migration.
|
|
|
11
11
|
### Directory Structure
|
|
12
12
|
```
|
|
13
13
|
static/
|
|
14
|
-
├── index.html
|
|
14
|
+
├── index.html // Main entry point
|
|
15
15
|
├── css/
|
|
16
16
|
├── js/
|
|
17
|
-
│ └── api.js
|
|
17
|
+
│ └── api.js // Centralized API calls
|
|
18
18
|
└── assets/
|
|
19
19
|
```
|
|
20
20
|
|
|
@@ -15,7 +15,7 @@ function "<name>" {
|
|
|
15
15
|
<type> <name> [filters=...] { description = "..." }
|
|
16
16
|
}
|
|
17
17
|
stack {
|
|
18
|
-
|
|
18
|
+
// Logic here
|
|
19
19
|
}
|
|
20
20
|
response = $result
|
|
21
21
|
}
|
|
@@ -110,21 +110,21 @@ stack {
|
|
|
110
110
|
### Loops
|
|
111
111
|
```xs
|
|
112
112
|
stack {
|
|
113
|
-
|
|
113
|
+
// For loop (count-based)
|
|
114
114
|
for (10) {
|
|
115
115
|
each as $i {
|
|
116
116
|
debug.log { value = $i }
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
-
|
|
120
|
+
// Foreach (array iteration)
|
|
121
121
|
foreach ($input.items) {
|
|
122
122
|
each as $item {
|
|
123
123
|
debug.log { value = $item.name }
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
-
|
|
127
|
+
// While loop
|
|
128
128
|
while ($counter < 5) {
|
|
129
129
|
each {
|
|
130
130
|
math.add $counter { value = 1 }
|
|
@@ -161,10 +161,10 @@ For complete error handling reference (preconditions, try-catch, throw, early re
|
|
|
161
161
|
Specify what the function returns:
|
|
162
162
|
|
|
163
163
|
```xs
|
|
164
|
-
response = $total
|
|
165
|
-
response = { success: true, data: $result }
|
|
166
|
-
response = $items|first
|
|
167
|
-
response = null
|
|
164
|
+
response = $total // Single variable
|
|
165
|
+
response = { success: true, data: $result } // Object literal
|
|
166
|
+
response = $items|first // With filter
|
|
167
|
+
response = null // No return value
|
|
168
168
|
```
|
|
169
169
|
|
|
170
170
|
---
|
|
@@ -182,20 +182,20 @@ cloud.elasticsearch.document {
|
|
|
182
182
|
|
|
183
183
|
### Key-Value Operations
|
|
184
184
|
```xs
|
|
185
|
-
|
|
185
|
+
// Set value
|
|
186
186
|
redis.set {
|
|
187
187
|
key = "user:123:session"
|
|
188
188
|
data = $session_data
|
|
189
|
-
ttl = 3600
|
|
189
|
+
ttl = 3600 // Expires in 1 hour
|
|
190
190
|
}
|
|
191
191
|
|
|
192
|
-
|
|
192
|
+
// Get value
|
|
193
193
|
redis.get { key = "user:123:session" } as $session
|
|
194
194
|
|
|
195
|
-
|
|
195
|
+
// Check exists
|
|
196
196
|
redis.has { key = "user:123:session" } as $exists
|
|
197
197
|
|
|
198
|
-
|
|
198
|
+
// Delete
|
|
199
199
|
redis.del { key = "user:123:session" }
|
|
200
200
|
```
|
|
201
201
|
|
|
@@ -147,18 +147,18 @@ mcp_server "CRM" {
|
|
|
147
147
|
### By Domain
|
|
148
148
|
```
|
|
149
149
|
mcp_servers/
|
|
150
|
-
├── support.xs
|
|
151
|
-
├── ecommerce.xs
|
|
152
|
-
├── analytics.xs
|
|
153
|
-
└── admin.xs
|
|
150
|
+
├── support.xs // Customer support tools
|
|
151
|
+
├── ecommerce.xs // Store management
|
|
152
|
+
├── analytics.xs // Reporting and metrics
|
|
153
|
+
└── admin.xs // Administrative functions
|
|
154
154
|
```
|
|
155
155
|
|
|
156
156
|
### By Access Level
|
|
157
157
|
```
|
|
158
158
|
mcp_servers/
|
|
159
|
-
├── public.xs
|
|
160
|
-
├── authenticated.xs
|
|
161
|
-
└── admin.xs
|
|
159
|
+
├── public.xs // Public-facing tools
|
|
160
|
+
├── authenticated.xs // Requires auth
|
|
161
|
+
└── admin.xs // Admin-only tools
|
|
162
162
|
```
|
|
163
163
|
|
|
164
164
|
---
|
|
@@ -44,24 +44,24 @@ var $total { value = `$input.qty * $input.price` }
|
|
|
44
44
|
|
|
45
45
|
### Comparison
|
|
46
46
|
```xs
|
|
47
|
-
$a == $b
|
|
48
|
-
$a != $b
|
|
49
|
-
$a > $b
|
|
50
|
-
$a >= $b
|
|
51
|
-
$a < $b
|
|
52
|
-
$a <= $b
|
|
47
|
+
$a == $b // Equal
|
|
48
|
+
$a != $b // Not equal
|
|
49
|
+
$a > $b // Greater than
|
|
50
|
+
$a >= $b // Greater or equal
|
|
51
|
+
$a < $b // Less than
|
|
52
|
+
$a <= $b // Less or equal
|
|
53
53
|
```
|
|
54
54
|
|
|
55
55
|
### Logical
|
|
56
56
|
```xs
|
|
57
|
-
$a && $b
|
|
58
|
-
$a || $b
|
|
59
|
-
!$a
|
|
57
|
+
$a && $b // AND
|
|
58
|
+
$a || $b // OR
|
|
59
|
+
!$a // NOT
|
|
60
60
|
```
|
|
61
61
|
|
|
62
62
|
### Null-Safe Comparisons (DB Queries)
|
|
63
63
|
```xs
|
|
64
|
-
|
|
64
|
+
// In db.query where clauses - ignore condition if value is null
|
|
65
65
|
$db.post.category ==? $input.category
|
|
66
66
|
$db.post.date >=? $input.start_date
|
|
67
67
|
```
|
|
@@ -88,11 +88,11 @@ $db.post.date >=? $input.start_date
|
|
|
88
88
|
|
|
89
89
|
### Array Math
|
|
90
90
|
```xs
|
|
91
|
-
[1,2,3,4]|sum
|
|
92
|
-
[1,2,3,4]|avg
|
|
93
|
-
[1,2,3,4]|product
|
|
94
|
-
[5,2,8,1]|array_min
|
|
95
|
-
[5,2,8,1]|array_max
|
|
91
|
+
[1,2,3,4]|sum // 10
|
|
92
|
+
[1,2,3,4]|avg // 2.5
|
|
93
|
+
[1,2,3,4]|product // 24
|
|
94
|
+
[5,2,8,1]|array_min // 1
|
|
95
|
+
[5,2,8,1]|array_max // 8
|
|
96
96
|
```
|
|
97
97
|
|
|
98
98
|
### Trigonometry
|
|
@@ -123,10 +123,10 @@ $db.post.date >=? $input.start_date
|
|
|
123
123
|
|
|
124
124
|
### Regex
|
|
125
125
|
```xs
|
|
126
|
-
"/pattern/"|regex_matches:"subject"
|
|
127
|
-
"/(\w+)/"|regex_get_first_match:"test"
|
|
128
|
-
"/\w+/"|regex_get_all_matches:"a b c"
|
|
129
|
-
"/\s+/"|regex_replace:"-":"a b"
|
|
126
|
+
"/pattern/"|regex_matches:"subject" // Boolean match
|
|
127
|
+
"/(\w+)/"|regex_get_first_match:"test" // First match
|
|
128
|
+
"/\w+/"|regex_get_all_matches:"a b c" // All matches
|
|
129
|
+
"/\s+/"|regex_replace:"-":"a b" // Replace: "a-b"
|
|
130
130
|
```
|
|
131
131
|
|
|
132
132
|
---
|
|
@@ -155,36 +155,36 @@ $db.post.date >=? $input.start_date
|
|
|
155
155
|
|
|
156
156
|
### Functional Operations
|
|
157
157
|
```xs
|
|
158
|
-
|
|
159
|
-
[{v:1},{v:2}]|map:$$.v*2
|
|
158
|
+
// Map - transform each element
|
|
159
|
+
[{v:1},{v:2}]|map:$$.v*2 // [2,4]
|
|
160
160
|
|
|
161
|
-
|
|
162
|
-
[1,2,3,4]|filter:$$%2==0
|
|
161
|
+
// Filter - keep matching elements
|
|
162
|
+
[1,2,3,4]|filter:$$%2==0 // [2,4]
|
|
163
163
|
|
|
164
|
-
|
|
165
|
-
[{id:1},{id:2}]|find:$$.id==2
|
|
164
|
+
// Find - first matching element
|
|
165
|
+
[{id:1},{id:2}]|find:$$.id==2 // {id:2}
|
|
166
166
|
|
|
167
|
-
|
|
168
|
-
[{id:1},{id:2}]|findIndex:$$.id==2
|
|
167
|
+
// FindIndex - index of first match
|
|
168
|
+
[{id:1},{id:2}]|findIndex:$$.id==2 // 1
|
|
169
169
|
|
|
170
|
-
|
|
171
|
-
[1,2,3]|some:$$>2
|
|
170
|
+
// Some - any element matches?
|
|
171
|
+
[1,2,3]|some:$$>2 // true
|
|
172
172
|
|
|
173
|
-
|
|
174
|
-
[2,4,6]|every:$$%2==0
|
|
173
|
+
// Every - all elements match?
|
|
174
|
+
[2,4,6]|every:$$%2==0 // true
|
|
175
175
|
|
|
176
|
-
|
|
177
|
-
[1,2,3,4]|reduce:$$+$result:0
|
|
176
|
+
// Reduce - accumulate to single value
|
|
177
|
+
[1,2,3,4]|reduce:$$+$result:0 // 10
|
|
178
178
|
```
|
|
179
179
|
|
|
180
180
|
### Grouping & Indexing
|
|
181
181
|
```xs
|
|
182
|
-
|
|
182
|
+
// Group by property
|
|
183
183
|
[{g:"a",v:1},{g:"b",v:2},{g:"a",v:3}]|index_by:g
|
|
184
|
-
|
|
184
|
+
// {"a":[{g:"a",v:1},{g:"a",v:3}],"b":[{g:"b",v:2}]}
|
|
185
185
|
|
|
186
|
-
|
|
187
|
-
[{n:"z"},{n:"a"}]|sort:n:text:false
|
|
186
|
+
// Sort
|
|
187
|
+
[{n:"z"},{n:"a"}]|sort:n:text:false // Ascending by n
|
|
188
188
|
```
|
|
189
189
|
|
|
190
190
|
---
|
|
@@ -205,9 +205,9 @@ $db.post.date >=? $input.start_date
|
|
|
205
205
|
|
|
206
206
|
### Conditional Set
|
|
207
207
|
```xs
|
|
208
|
-
{a:1}|set_conditional:"b":2:true
|
|
209
|
-
{a:1}|set_ifnotempty:"b":"val"
|
|
210
|
-
{a:1}|set_ifnotnull:"b":$var
|
|
208
|
+
{a:1}|set_conditional:"b":2:true // {a:1,b:2} if condition true
|
|
209
|
+
{a:1}|set_ifnotempty:"b":"val" // Set only if val not empty
|
|
210
|
+
{a:1}|set_ifnotnull:"b":$var // Set only if $var not null
|
|
211
211
|
```
|
|
212
212
|
|
|
213
213
|
---
|
|
@@ -229,8 +229,8 @@ $db.post.date >=? $input.start_date
|
|
|
229
229
|
|
|
230
230
|
### Null Handling
|
|
231
231
|
```xs
|
|
232
|
-
null|first_notnull:0
|
|
233
|
-
""|first_notempty:"default"
|
|
232
|
+
null|first_notnull:0 // 0
|
|
233
|
+
""|first_notempty:"default" // "default"
|
|
234
234
|
```
|
|
235
235
|
|
|
236
236
|
---
|
|
@@ -249,12 +249,12 @@ null|first_notnull:0 # 0
|
|
|
249
249
|
|
|
250
250
|
### Timestamp Parts
|
|
251
251
|
```xs
|
|
252
|
-
$ts|timestamp_year
|
|
253
|
-
$ts|timestamp_month
|
|
254
|
-
$ts|timestamp_day_of_month
|
|
255
|
-
$ts|timestamp_hour
|
|
256
|
-
$ts|timestamp_minute
|
|
257
|
-
$ts|timestamp_day_of_week
|
|
252
|
+
$ts|timestamp_year // Year
|
|
253
|
+
$ts|timestamp_month // Month (1-12)
|
|
254
|
+
$ts|timestamp_day_of_month // Day (1-31)
|
|
255
|
+
$ts|timestamp_hour // Hour (0-23)
|
|
256
|
+
$ts|timestamp_minute // Minute (0-59)
|
|
257
|
+
$ts|timestamp_day_of_week // Day (0=Sunday)
|
|
258
258
|
```
|
|
259
259
|
|
|
260
260
|
---
|
|
@@ -10,9 +10,9 @@ Database table definitions in XanoScript.
|
|
|
10
10
|
|
|
11
11
|
```xs
|
|
12
12
|
table "<name>" {
|
|
13
|
-
auth = false
|
|
13
|
+
auth = false // true if used for authentication
|
|
14
14
|
schema {
|
|
15
|
-
int id
|
|
15
|
+
int id // Primary key (required)
|
|
16
16
|
text name filters=trim
|
|
17
17
|
timestamp created_at?=now
|
|
18
18
|
}
|
|
@@ -72,10 +72,10 @@ schema {
|
|
|
72
72
|
### Optional & Defaults
|
|
73
73
|
```xs
|
|
74
74
|
schema {
|
|
75
|
-
text nickname?
|
|
76
|
-
timestamp created_at?=now
|
|
77
|
-
bool is_active?=true
|
|
78
|
-
int status?=0
|
|
75
|
+
text nickname? // Optional, no default
|
|
76
|
+
timestamp created_at?=now // Optional, defaults to current time
|
|
77
|
+
bool is_active?=true // Optional, defaults to true
|
|
78
|
+
int status?=0 // Optional, defaults to 0
|
|
79
79
|
}
|
|
80
80
|
```
|
|
81
81
|
|
|
@@ -139,7 +139,7 @@ schema {
|
|
|
139
139
|
### Vector Fields
|
|
140
140
|
```xs
|
|
141
141
|
schema {
|
|
142
|
-
vector embedding
|
|
142
|
+
vector embedding // For AI/ML embeddings
|
|
143
143
|
}
|
|
144
144
|
```
|
|
145
145
|
|
package/xanoscript_docs/tasks.md
CHANGED
|
@@ -34,11 +34,11 @@ table_trigger "<name>" {
|
|
|
34
34
|
tags = ["tag1", "tag2"]
|
|
35
35
|
|
|
36
36
|
input {
|
|
37
|
-
|
|
37
|
+
// Define input parameters
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
stack {
|
|
41
|
-
|
|
41
|
+
// Logic to execute when triggered
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
history = 100
|
|
@@ -118,11 +118,11 @@ realtime_trigger "<name>" {
|
|
|
118
118
|
tags = ["tag1", "tag2"]
|
|
119
119
|
|
|
120
120
|
input {
|
|
121
|
-
|
|
121
|
+
// Define input parameters
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
stack {
|
|
125
|
-
|
|
125
|
+
// Logic to execute when triggered
|
|
126
126
|
}
|
|
127
127
|
|
|
128
128
|
response = $result
|
|
@@ -211,11 +211,11 @@ workspace_trigger "<name>" {
|
|
|
211
211
|
tags = ["tag1", "tag2"]
|
|
212
212
|
|
|
213
213
|
input {
|
|
214
|
-
|
|
214
|
+
// Define input parameters
|
|
215
215
|
}
|
|
216
216
|
|
|
217
217
|
stack {
|
|
218
|
-
|
|
218
|
+
// Logic to execute when triggered
|
|
219
219
|
}
|
|
220
220
|
|
|
221
221
|
history = 100
|
|
@@ -292,11 +292,11 @@ agent_trigger "<name>" {
|
|
|
292
292
|
tags = ["tag1", "tag2"]
|
|
293
293
|
|
|
294
294
|
input {
|
|
295
|
-
|
|
295
|
+
// Define input parameters
|
|
296
296
|
}
|
|
297
297
|
|
|
298
298
|
stack {
|
|
299
|
-
|
|
299
|
+
// Logic to execute when triggered
|
|
300
300
|
}
|
|
301
301
|
|
|
302
302
|
response = $result
|
|
@@ -383,11 +383,11 @@ mcp_server_trigger "<name>" {
|
|
|
383
383
|
tags = ["tag1", "tag2"]
|
|
384
384
|
|
|
385
385
|
input {
|
|
386
|
-
|
|
386
|
+
// Define input parameters
|
|
387
387
|
}
|
|
388
388
|
|
|
389
389
|
stack {
|
|
390
|
-
|
|
390
|
+
// Logic to execute when triggered
|
|
391
391
|
}
|
|
392
392
|
|
|
393
393
|
response = $result
|
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
|
```
|