@xano/developer-mcp 1.0.33 → 1.0.34
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/xanoscript.js
CHANGED
|
@@ -21,6 +21,11 @@ export const XANOSCRIPT_DOCS_V2 = {
|
|
|
21
21
|
applyTo: ["**/*.xs"],
|
|
22
22
|
description: "Expressions, operators, and filters for all XanoScript code",
|
|
23
23
|
},
|
|
24
|
+
quickstart: {
|
|
25
|
+
file: "quickstart.md",
|
|
26
|
+
applyTo: ["**/*.xs"],
|
|
27
|
+
description: "Common patterns, quick reference, and common mistakes to avoid",
|
|
28
|
+
},
|
|
24
29
|
types: {
|
|
25
30
|
file: "types.md",
|
|
26
31
|
applyTo: ["functions/**/*.xs", "apis/**/*.xs", "tools/**/*.xs", "agents/**/*.xs"],
|
package/dist/xanoscript.test.js
CHANGED
|
@@ -11,6 +11,7 @@ describe("xanoscript module", () => {
|
|
|
11
11
|
const expectedTopics = [
|
|
12
12
|
"readme",
|
|
13
13
|
"syntax",
|
|
14
|
+
"quickstart",
|
|
14
15
|
"types",
|
|
15
16
|
"tables",
|
|
16
17
|
"functions",
|
|
@@ -135,9 +136,10 @@ describe("xanoscript module", () => {
|
|
|
135
136
|
const result = getDocsForFilePath("apis/test.xs");
|
|
136
137
|
expect(result).not.toContain("readme");
|
|
137
138
|
});
|
|
138
|
-
it("should
|
|
139
|
+
it("should include syntax and quickstart for .xs files", () => {
|
|
139
140
|
const result = getDocsForFilePath("some/random/file.xs");
|
|
140
|
-
expect(result
|
|
141
|
+
expect(result).toContain("syntax");
|
|
142
|
+
expect(result).toContain("quickstart");
|
|
141
143
|
});
|
|
142
144
|
});
|
|
143
145
|
describe("extractQuickReference", () => {
|
|
@@ -142,18 +142,35 @@ applyTo: "function/**/*.xs"
|
|
|
142
142
|
|
|
143
143
|
This helps AI tools apply the correct documentation based on the file being edited.
|
|
144
144
|
|
|
145
|
+
## Getting Started
|
|
146
|
+
|
|
147
|
+
For common patterns and quick examples, use:
|
|
148
|
+
```
|
|
149
|
+
xanoscript_docs({ topic: "quickstart" })
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
This includes:
|
|
153
|
+
- Variable declaration patterns
|
|
154
|
+
- Conditional logic (if/elseif/else)
|
|
155
|
+
- API requests with error handling
|
|
156
|
+
- Database CRUD operations
|
|
157
|
+
- Common mistakes to avoid
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
145
161
|
## Documentation Index
|
|
146
162
|
|
|
147
163
|
Use `xanoscript_docs({ topic: "<topic>" })` to retrieve documentation.
|
|
148
164
|
|
|
149
165
|
### Core Language
|
|
150
166
|
|
|
151
|
-
| Topic
|
|
152
|
-
|
|
|
153
|
-
| `
|
|
154
|
-
| `
|
|
155
|
-
| `
|
|
156
|
-
| `
|
|
167
|
+
| Topic | Description |
|
|
168
|
+
| ------------ | ---------------------------------------------------- |
|
|
169
|
+
| `quickstart` | Common patterns, quick examples, mistakes to avoid |
|
|
170
|
+
| `syntax` | Expressions, operators, filters, system variables |
|
|
171
|
+
| `types` | Data types, validation, input blocks |
|
|
172
|
+
| `functions` | Reusable function stacks, async, loops |
|
|
173
|
+
| `schema` | Runtime schema parsing and validation |
|
|
157
174
|
|
|
158
175
|
### Data
|
|
159
176
|
|
|
@@ -210,3 +227,47 @@ Use `xanoscript_docs({ topic: "<topic>" })` to retrieve documentation.
|
|
|
210
227
|
| ------------- | ------------------------------------------------------------ |
|
|
211
228
|
| `performance` | Performance optimization best practices |
|
|
212
229
|
| `security` | Security best practices for authentication and authorization |
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## Example Implementations
|
|
234
|
+
|
|
235
|
+
Common integration patterns you can reference:
|
|
236
|
+
|
|
237
|
+
### External API Integrations
|
|
238
|
+
- **OpenAI/ChatGPT**: Use `api.request` with POST to `/v1/chat/completions`
|
|
239
|
+
- **Stripe**: Use `api.request` with form-encoded params for payments
|
|
240
|
+
- **SendGrid/Resend**: Use `api.request` or `util.send_email` for emails
|
|
241
|
+
- **Slack/Discord**: Use `api.request` with webhook URLs
|
|
242
|
+
- **Twilio**: Use `api.request` with Basic auth for SMS
|
|
243
|
+
|
|
244
|
+
### Common Pattern: API Integration Function
|
|
245
|
+
|
|
246
|
+
```xs
|
|
247
|
+
function "call_external_api" {
|
|
248
|
+
input {
|
|
249
|
+
text endpoint
|
|
250
|
+
object payload
|
|
251
|
+
}
|
|
252
|
+
stack {
|
|
253
|
+
api.request {
|
|
254
|
+
url = $env.API_BASE_URL ~ $input.endpoint
|
|
255
|
+
method = "POST"
|
|
256
|
+
params = $input.payload
|
|
257
|
+
headers = [
|
|
258
|
+
"Content-Type: application/json",
|
|
259
|
+
"Authorization: Bearer " ~ $env.API_KEY
|
|
260
|
+
]
|
|
261
|
+
timeout = 30
|
|
262
|
+
} as $api_result
|
|
263
|
+
|
|
264
|
+
precondition ($api_result.response.status >= 200 && $api_result.response.status < 300) {
|
|
265
|
+
error_type = "standard"
|
|
266
|
+
error = "API error: " ~ ($api_result.response.status|to_text)
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
response = $api_result.response.result
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
For more patterns, see `xanoscript_docs({ topic: "quickstart" })` or `xanoscript_docs({ topic: "integrations" })`.
|
|
@@ -575,22 +575,92 @@ util.send_email {
|
|
|
575
575
|
|
|
576
576
|
---
|
|
577
577
|
|
|
578
|
-
## External APIs
|
|
578
|
+
## External APIs (api.request)
|
|
579
579
|
|
|
580
580
|
Make HTTP requests to external APIs.
|
|
581
581
|
|
|
582
|
+
### Quick Reference
|
|
583
|
+
|
|
582
584
|
```xs
|
|
583
585
|
api.request {
|
|
584
|
-
url = "https://api.example.com/
|
|
585
|
-
method = "POST"
|
|
586
|
-
params =
|
|
586
|
+
url = "https://api.example.com/endpoint"
|
|
587
|
+
method = "POST" // GET, POST, PUT, PATCH, DELETE
|
|
588
|
+
params = $payload // Request body for POST/PUT/PATCH
|
|
587
589
|
headers = ["Content-Type: application/json", "Authorization: Bearer " ~ $env.API_KEY]
|
|
588
|
-
timeout = 30
|
|
590
|
+
timeout = 30 // Timeout in seconds
|
|
589
591
|
} as $api_result
|
|
592
|
+
|
|
593
|
+
// Access response
|
|
594
|
+
$api_result.response.status // HTTP status code (200, 404, etc.)
|
|
595
|
+
$api_result.response.result // Response body (auto-parsed JSON)
|
|
596
|
+
$api_result.response.headers // Response headers array
|
|
590
597
|
```
|
|
591
598
|
|
|
599
|
+
> **Important:** The `params` parameter is used for the **request body** (POST/PUT/PATCH), not query parameters. This naming is counterintuitive but consistent across XanoScript.
|
|
600
|
+
|
|
592
601
|
> **Note:** The `headers` parameter expects an array of text strings, where each string contains the header name and value separated by a colon (e.g., `["Content-Type: application/json", "X-Custom-Header: value"]`).
|
|
593
602
|
|
|
603
|
+
### GET Request
|
|
604
|
+
|
|
605
|
+
```xs
|
|
606
|
+
api.request {
|
|
607
|
+
url = "https://api.example.com/users?page=1&limit=10"
|
|
608
|
+
method = "GET"
|
|
609
|
+
headers = ["Authorization: Bearer " ~ $env.API_KEY]
|
|
610
|
+
} as $api_result
|
|
611
|
+
|
|
612
|
+
var $users { value = $api_result.response.result }
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
### POST Request with JSON Body
|
|
616
|
+
|
|
617
|
+
```xs
|
|
618
|
+
var $payload {
|
|
619
|
+
value = {
|
|
620
|
+
name: $input.name,
|
|
621
|
+
email: $input.email
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
api.request {
|
|
626
|
+
url = "https://api.example.com/users"
|
|
627
|
+
method = "POST"
|
|
628
|
+
params = $payload
|
|
629
|
+
headers = ["Content-Type: application/json", "Authorization: Bearer " ~ $env.API_KEY]
|
|
630
|
+
} as $api_result
|
|
631
|
+
|
|
632
|
+
// Check for success
|
|
633
|
+
precondition ($api_result.response.status == 201) {
|
|
634
|
+
error_type = "standard"
|
|
635
|
+
error = "Failed to create user: " ~ ($api_result.response.result|json_encode)
|
|
636
|
+
}
|
|
637
|
+
```
|
|
638
|
+
|
|
639
|
+
### Error Handling Pattern
|
|
640
|
+
|
|
641
|
+
```xs
|
|
642
|
+
api.request {
|
|
643
|
+
url = "https://api.example.com/data"
|
|
644
|
+
method = "GET"
|
|
645
|
+
timeout = 30
|
|
646
|
+
} as $api_result
|
|
647
|
+
|
|
648
|
+
conditional {
|
|
649
|
+
if ($api_result.response.status >= 200 && $api_result.response.status < 300) {
|
|
650
|
+
var $data { value = $api_result.response.result }
|
|
651
|
+
}
|
|
652
|
+
elseif ($api_result.response.status == 404) {
|
|
653
|
+
throw { name = "NotFound", value = "Resource not found" }
|
|
654
|
+
}
|
|
655
|
+
else {
|
|
656
|
+
throw {
|
|
657
|
+
name = "APIError",
|
|
658
|
+
value = "API returned status " ~ ($api_result.response.status|to_text)
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
```
|
|
663
|
+
|
|
594
664
|
### Response Structure
|
|
595
665
|
|
|
596
666
|
The `api.request` statement returns an object with both request and response details:
|
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
---
|
|
2
|
+
applyTo: "**/*.xs"
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Quickstart & Common Patterns
|
|
6
|
+
|
|
7
|
+
Essential patterns for XanoScript development. Use this as a quick reference for frequently-used code patterns.
|
|
8
|
+
|
|
9
|
+
## Quick Reference
|
|
10
|
+
|
|
11
|
+
### Variable Declaration
|
|
12
|
+
```xs
|
|
13
|
+
var $name { value = "initial value" }
|
|
14
|
+
var $count { value = 0 }
|
|
15
|
+
var $data { value = { key: "value" } }
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### Conditional Logic
|
|
19
|
+
```xs
|
|
20
|
+
conditional {
|
|
21
|
+
if (`$status == "active"`) {
|
|
22
|
+
var $result { value = "Active user" }
|
|
23
|
+
}
|
|
24
|
+
elseif (`$status == "pending"`) {
|
|
25
|
+
var $result { value = "Pending approval" }
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
var $result { value = "Unknown status" }
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### API Request with Error Handling
|
|
34
|
+
```xs
|
|
35
|
+
api.request {
|
|
36
|
+
url = "https://api.example.com/data"
|
|
37
|
+
method = "POST"
|
|
38
|
+
params = $payload
|
|
39
|
+
headers = ["Content-Type: application/json", "Authorization: Bearer " ~ $env.API_KEY]
|
|
40
|
+
} as $api_result
|
|
41
|
+
|
|
42
|
+
precondition ($api_result.response.status == 200) {
|
|
43
|
+
error_type = "standard"
|
|
44
|
+
error = "API request failed"
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
var $data { value = $api_result.response.result }
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### String Concatenation
|
|
51
|
+
```xs
|
|
52
|
+
var $greeting { value = "Hello, " ~ $input.name ~ "!" }
|
|
53
|
+
|
|
54
|
+
// With filters (use parentheses)
|
|
55
|
+
var $message { value = "Status: " ~ ($status|to_text) ~ " - " ~ ($data|json_encode) }
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Common Patterns
|
|
61
|
+
|
|
62
|
+
### 1. Input Validation
|
|
63
|
+
|
|
64
|
+
```xs
|
|
65
|
+
// Required field check
|
|
66
|
+
precondition ($input.email != null && $input.email != "") {
|
|
67
|
+
error_type = "inputerror"
|
|
68
|
+
error = "Email is required"
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Format validation
|
|
72
|
+
precondition ($input.email|contains:"@") {
|
|
73
|
+
error_type = "inputerror"
|
|
74
|
+
error = "Invalid email format"
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### 2. Database CRUD
|
|
79
|
+
|
|
80
|
+
```xs
|
|
81
|
+
// Create
|
|
82
|
+
db.add "user" {
|
|
83
|
+
data = { name: $input.name, email: $input.email }
|
|
84
|
+
} as $new_user
|
|
85
|
+
|
|
86
|
+
// Read one
|
|
87
|
+
db.get "user" {
|
|
88
|
+
where = $db.user.id == $input.id
|
|
89
|
+
} as $user
|
|
90
|
+
|
|
91
|
+
// Read many
|
|
92
|
+
db.query "user" {
|
|
93
|
+
where = $db.user.is_active == true
|
|
94
|
+
order = [{ field: created_at, direction: desc }]
|
|
95
|
+
paging = { limit: 10, offset: 0 }
|
|
96
|
+
} as $users
|
|
97
|
+
|
|
98
|
+
// Update
|
|
99
|
+
db.edit "user" {
|
|
100
|
+
where = $db.user.id == $input.id
|
|
101
|
+
data = { name: $input.name }
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Delete
|
|
105
|
+
db.delete "user" {
|
|
106
|
+
where = $db.user.id == $input.id
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### 3. Optional Field Handling
|
|
111
|
+
|
|
112
|
+
```xs
|
|
113
|
+
// Build object with optional fields
|
|
114
|
+
var $data { value = { required_field: $input.required } }
|
|
115
|
+
|
|
116
|
+
conditional {
|
|
117
|
+
if ($input.optional_field != null) {
|
|
118
|
+
var.update $data { value = $data|set:"optional_field":$input.optional_field }
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Or use set_ifnotnull
|
|
123
|
+
var $data {
|
|
124
|
+
value = { required: $input.required }|set_ifnotnull:"optional":$input.optional
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### 4. Loop Through Array
|
|
129
|
+
|
|
130
|
+
```xs
|
|
131
|
+
// Using each
|
|
132
|
+
each ($items as $item) {
|
|
133
|
+
debug.log { value = $item.name }
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Using map filter
|
|
137
|
+
var $names { value = $items|map:$$.name }
|
|
138
|
+
|
|
139
|
+
// Using filter
|
|
140
|
+
var $active_items { value = $items|filter:$$.is_active == true }
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### 5. Error Handling with Try-Catch
|
|
144
|
+
|
|
145
|
+
```xs
|
|
146
|
+
try_catch {
|
|
147
|
+
try {
|
|
148
|
+
api.request {
|
|
149
|
+
url = "https://api.example.com/risky"
|
|
150
|
+
method = "GET"
|
|
151
|
+
} as $result
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
debug.log { value = "Request failed, using fallback" }
|
|
155
|
+
var $result { value = { response: { result: null } } }
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### 6. Authentication Check
|
|
161
|
+
|
|
162
|
+
```xs
|
|
163
|
+
// Require authenticated user
|
|
164
|
+
precondition ($auth.id != null) {
|
|
165
|
+
error_type = "accessdenied"
|
|
166
|
+
error = "Authentication required"
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Check user owns resource
|
|
170
|
+
db.get "post" {
|
|
171
|
+
where = $db.post.id == $input.post_id
|
|
172
|
+
} as $post
|
|
173
|
+
|
|
174
|
+
precondition ($post.user_id == $auth.id) {
|
|
175
|
+
error_type = "accessdenied"
|
|
176
|
+
error = "You can only edit your own posts"
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### 7. Pagination
|
|
181
|
+
|
|
182
|
+
```xs
|
|
183
|
+
var $page { value = $input.page ?? 1 }
|
|
184
|
+
var $limit { value = $input.limit ?? 20 }
|
|
185
|
+
var $offset { value = ($page - 1) * $limit }
|
|
186
|
+
|
|
187
|
+
db.query "item" {
|
|
188
|
+
where = $db.item.is_active == true
|
|
189
|
+
order = [{ field: created_at, direction: desc }]
|
|
190
|
+
paging = { limit: $limit, offset: $offset }
|
|
191
|
+
count = true
|
|
192
|
+
} as $result
|
|
193
|
+
|
|
194
|
+
response = {
|
|
195
|
+
items: $result.items,
|
|
196
|
+
total: $result.count,
|
|
197
|
+
page: $page,
|
|
198
|
+
pages: ($result.count / $limit)|ceil
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### 8. Building Complex Objects
|
|
203
|
+
|
|
204
|
+
```xs
|
|
205
|
+
// Step by step
|
|
206
|
+
var $response { value = {} }
|
|
207
|
+
var.update $response { value = $response|set:"user":$user }
|
|
208
|
+
var.update $response { value = $response|set:"posts":$posts }
|
|
209
|
+
var.update $response { value = $response|set:"stats":{ count: $posts|count } }
|
|
210
|
+
|
|
211
|
+
// Or all at once
|
|
212
|
+
var $response {
|
|
213
|
+
value = {
|
|
214
|
+
user: $user,
|
|
215
|
+
posts: $posts,
|
|
216
|
+
stats: { count: $posts|count }
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### 9. Date/Time Operations
|
|
222
|
+
|
|
223
|
+
```xs
|
|
224
|
+
// Current timestamp
|
|
225
|
+
var $now { value = now }
|
|
226
|
+
|
|
227
|
+
// Format for display
|
|
228
|
+
var $formatted { value = now|format_timestamp:"Y-m-d H:i:s":"UTC" }
|
|
229
|
+
|
|
230
|
+
// Relative time
|
|
231
|
+
var $yesterday { value = now|transform_timestamp:"-1 day" }
|
|
232
|
+
var $next_week { value = now|transform_timestamp:"+7 days" }
|
|
233
|
+
|
|
234
|
+
// Compare dates
|
|
235
|
+
db.query "event" {
|
|
236
|
+
where = $db.event.start_date >= now
|
|
237
|
+
} as $upcoming_events
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### 10. JSON API Response
|
|
241
|
+
|
|
242
|
+
```xs
|
|
243
|
+
api.request {
|
|
244
|
+
url = "https://api.openai.com/v1/chat/completions"
|
|
245
|
+
method = "POST"
|
|
246
|
+
params = {
|
|
247
|
+
model: "gpt-4",
|
|
248
|
+
messages: [{ role: "user", content: $input.prompt }]
|
|
249
|
+
}
|
|
250
|
+
headers = [
|
|
251
|
+
"Content-Type: application/json",
|
|
252
|
+
"Authorization: Bearer " ~ $env.OPENAI_API_KEY
|
|
253
|
+
]
|
|
254
|
+
} as $api_result
|
|
255
|
+
|
|
256
|
+
conditional {
|
|
257
|
+
if ($api_result.response.status == 200) {
|
|
258
|
+
var $answer { value = $api_result.response.result.choices|first|get:"message"|get:"content" }
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
throw {
|
|
262
|
+
name = "APIError",
|
|
263
|
+
value = "OpenAI API error: " ~ ($api_result.response.status|to_text)
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## Common Mistakes
|
|
272
|
+
|
|
273
|
+
### 1. Using `else if` instead of `elseif`
|
|
274
|
+
```xs
|
|
275
|
+
// ❌ Wrong
|
|
276
|
+
conditional {
|
|
277
|
+
if (...) { }
|
|
278
|
+
else if (...) { } // Parse error!
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// ✅ Correct
|
|
282
|
+
conditional {
|
|
283
|
+
if (...) { }
|
|
284
|
+
elseif (...) { }
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### 2. Missing parentheses in filter concatenation
|
|
289
|
+
```xs
|
|
290
|
+
// ❌ Wrong
|
|
291
|
+
var $msg { value = $status|to_text ~ " - " ~ $data|json_encode }
|
|
292
|
+
|
|
293
|
+
// ✅ Correct
|
|
294
|
+
var $msg { value = ($status|to_text) ~ " - " ~ ($data|json_encode) }
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
### 3. Using `body` instead of `params` for api.request
|
|
298
|
+
```xs
|
|
299
|
+
// ❌ Wrong
|
|
300
|
+
api.request {
|
|
301
|
+
url = "..."
|
|
302
|
+
method = "POST"
|
|
303
|
+
body = $payload // "body" is not valid!
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// ✅ Correct
|
|
307
|
+
api.request {
|
|
308
|
+
url = "..."
|
|
309
|
+
method = "POST"
|
|
310
|
+
params = $payload // Use "params" for request body
|
|
311
|
+
}
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
### 4. Using `default` filter (doesn't exist)
|
|
315
|
+
```xs
|
|
316
|
+
// ❌ Wrong
|
|
317
|
+
var $value { value = $input.optional|default:"fallback" }
|
|
318
|
+
|
|
319
|
+
// ✅ Correct
|
|
320
|
+
var $value { value = $input.optional|first_notnull:"fallback" }
|
|
321
|
+
// or
|
|
322
|
+
var $value { value = $input.optional ?? "fallback" }
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
### 5. Using $env in run.job input blocks
|
|
326
|
+
```xs
|
|
327
|
+
// ❌ Wrong - $env not allowed in input blocks
|
|
328
|
+
run.job "my_job" {
|
|
329
|
+
input {
|
|
330
|
+
text api_key = $env.API_KEY
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// ✅ Correct - use $env in the stack
|
|
335
|
+
run.job "my_job" {
|
|
336
|
+
stack {
|
|
337
|
+
var $api_key { value = $env.API_KEY }
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
```
|
|
@@ -21,12 +21,67 @@ Complete reference for XanoScript expressions, operators, and filters.
|
|
|
21
21
|
| Filter | Purpose | Example |
|
|
22
22
|
|--------|---------|---------|
|
|
23
23
|
| `trim` | Remove whitespace | `$s\|trim` |
|
|
24
|
-
| `
|
|
24
|
+
| `to_lower` / `to_upper` | Case conversion | `$s\|to_lower` |
|
|
25
25
|
| `first` / `last` | Array endpoints | `$arr\|first` |
|
|
26
26
|
| `count` | Array/object length | `$arr\|count` |
|
|
27
27
|
| `get` | Object property | `$obj\|get:"key"` |
|
|
28
28
|
| `set` | Set property | `$obj\|set:"key":"val"` |
|
|
29
29
|
| `json_encode` / `json_decode` | JSON conversion | `$obj\|json_encode` |
|
|
30
|
+
| `to_text` / `to_int` | Type conversion | `$num\|to_text` |
|
|
31
|
+
|
|
32
|
+
> **Note:** There is no `default` filter. Use conditional blocks or `first_notnull`/`first_notempty` instead.
|
|
33
|
+
|
|
34
|
+
### String Concatenation with Filters
|
|
35
|
+
|
|
36
|
+
When concatenating strings that use filters, wrap each filtered expression in parentheses:
|
|
37
|
+
|
|
38
|
+
```xs
|
|
39
|
+
// ✅ Correct - parentheses around filtered expressions
|
|
40
|
+
var $message {
|
|
41
|
+
value = ($status|to_text) ~ ": " ~ ($data|json_encode)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// ❌ Incorrect - missing parentheses causes parse error
|
|
45
|
+
var $message {
|
|
46
|
+
value = $status|to_text ~ ": " ~ $data|json_encode
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Conditional Blocks
|
|
53
|
+
|
|
54
|
+
Use `conditional` blocks for if/elseif/else logic:
|
|
55
|
+
|
|
56
|
+
```xs
|
|
57
|
+
conditional {
|
|
58
|
+
if (`$status == "success"`) {
|
|
59
|
+
var $message { value = "All good!" }
|
|
60
|
+
}
|
|
61
|
+
elseif (`$status == "pending"`) {
|
|
62
|
+
var $message { value = "Please wait..." }
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
var $message { value = "Unknown status" }
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
> **Important:** Use `elseif` (one word), not `else if` or `else { if (...) }`. Nested `if` inside `else` blocks is not supported.
|
|
71
|
+
|
|
72
|
+
### Conditional as Expression
|
|
73
|
+
|
|
74
|
+
Use conditional blocks inline to return values:
|
|
75
|
+
|
|
76
|
+
```xs
|
|
77
|
+
var $tier_limit {
|
|
78
|
+
value = conditional {
|
|
79
|
+
if ($auth.tier == "premium") { 1000 }
|
|
80
|
+
elseif ($auth.tier == "pro") { 500 }
|
|
81
|
+
else { 100 }
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
```
|
|
30
85
|
|
|
31
86
|
---
|
|
32
87
|
|
|
@@ -431,6 +486,32 @@ var $client_ip { value = $env.$remote_ip }
|
|
|
431
486
|
var $method { value = $env.$request_method }
|
|
432
487
|
var $headers { value = $env.$http_headers }
|
|
433
488
|
var $current_branch { value = $env.$branch }
|
|
489
|
+
|
|
490
|
+
// Custom environment variables (set in Xano dashboard)
|
|
491
|
+
var $api_key { value = $env.MY_API_KEY }
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
### $env Limitations
|
|
495
|
+
|
|
496
|
+
> **Important:** `$env` variables cannot be used in `run.job` or `run.service` input blocks. Input values must be constants.
|
|
497
|
+
|
|
498
|
+
```xs
|
|
499
|
+
// ❌ Invalid - $env not allowed in run.job input
|
|
500
|
+
run.job "my_job" {
|
|
501
|
+
input {
|
|
502
|
+
text api_key = $env.API_KEY // Error!
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
// ✅ Valid - access $env inside the stack instead
|
|
507
|
+
run.job "my_job" {
|
|
508
|
+
input {
|
|
509
|
+
text api_key // No default value
|
|
510
|
+
}
|
|
511
|
+
stack {
|
|
512
|
+
var $key { value = $env.API_KEY }
|
|
513
|
+
}
|
|
514
|
+
}
|
|
434
515
|
```
|
|
435
516
|
|
|
436
517
|
---
|
package/package.json
CHANGED