@xano/developer-mcp 1.0.8 → 1.0.9
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 +16 -0
- package/dist/index.js +35 -0
- package/dist/templates/xanoscript-index.js +7 -0
- package/package.json +1 -1
- package/xanoscript_docs/README.md +38 -5
- package/xanoscript_docs/addons.md +285 -0
- package/xanoscript_docs/agents.md +84 -0
- package/xanoscript_docs/database.md +160 -0
- package/xanoscript_docs/debugging.md +342 -0
- package/xanoscript_docs/functions.md +172 -0
- package/xanoscript_docs/integrations.md +376 -7
- package/xanoscript_docs/performance.md +407 -0
- package/xanoscript_docs/realtime.md +382 -0
- package/xanoscript_docs/schema.md +292 -0
- package/xanoscript_docs/security.md +550 -0
- package/xanoscript_docs/streaming.md +318 -0
- package/xanoscript_docs/syntax.md +267 -0
- package/xanoscript_docs/types.md +66 -21
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
---
|
|
2
|
+
applyTo: "functions/**/*.xs, apis/**/*.xs"
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Streaming Operations
|
|
6
|
+
|
|
7
|
+
Stream data from files, requests, and to API responses.
|
|
8
|
+
|
|
9
|
+
## Quick Reference
|
|
10
|
+
|
|
11
|
+
| Operation | Purpose | Input |
|
|
12
|
+
|-----------|---------|-------|
|
|
13
|
+
| `stream.from_csv` | Parse CSV stream | File or string |
|
|
14
|
+
| `stream.from_jsonl` | Parse JSONL stream | File or string |
|
|
15
|
+
| `stream.from_request` | Stream HTTP request body | Request |
|
|
16
|
+
| `api.stream` | Stream response to client | Data |
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## stream.from_csv
|
|
21
|
+
|
|
22
|
+
Parse CSV data as a stream, processing rows one at a time without loading entire file into memory.
|
|
23
|
+
|
|
24
|
+
```xs
|
|
25
|
+
stream.from_csv {
|
|
26
|
+
value = $input.csv_file
|
|
27
|
+
headers = true
|
|
28
|
+
delimiter = ","
|
|
29
|
+
enclosure = "\""
|
|
30
|
+
} as $row {
|
|
31
|
+
// Process each row
|
|
32
|
+
db.add "import_record" {
|
|
33
|
+
data = {
|
|
34
|
+
name: $row.name,
|
|
35
|
+
email: $row.email,
|
|
36
|
+
created_at: now
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Parameters
|
|
43
|
+
|
|
44
|
+
| Parameter | Type | Default | Description |
|
|
45
|
+
|-----------|------|---------|-------------|
|
|
46
|
+
| `value` | file/text | required | CSV file or string |
|
|
47
|
+
| `headers` | bool | `true` | First row contains headers |
|
|
48
|
+
| `delimiter` | text | `,` | Field delimiter |
|
|
49
|
+
| `enclosure` | text | `"` | Field enclosure character |
|
|
50
|
+
| `escape` | text | `\` | Escape character |
|
|
51
|
+
|
|
52
|
+
### With Custom Headers
|
|
53
|
+
|
|
54
|
+
```xs
|
|
55
|
+
stream.from_csv {
|
|
56
|
+
value = $input.file
|
|
57
|
+
headers = false
|
|
58
|
+
} as $row {
|
|
59
|
+
// Access by index: $row.0, $row.1, etc.
|
|
60
|
+
var $name { value = $row.0 }
|
|
61
|
+
var $email { value = $row.1 }
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## stream.from_jsonl
|
|
68
|
+
|
|
69
|
+
Parse JSON Lines (newline-delimited JSON) as a stream.
|
|
70
|
+
|
|
71
|
+
```xs
|
|
72
|
+
stream.from_jsonl {
|
|
73
|
+
value = $input.jsonl_file
|
|
74
|
+
} as $record {
|
|
75
|
+
// Each $record is a parsed JSON object
|
|
76
|
+
db.add "event" {
|
|
77
|
+
data = {
|
|
78
|
+
event_type: $record.type,
|
|
79
|
+
payload: $record.data,
|
|
80
|
+
timestamp: $record.ts
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Parameters
|
|
87
|
+
|
|
88
|
+
| Parameter | Type | Default | Description |
|
|
89
|
+
|-----------|------|---------|-------------|
|
|
90
|
+
| `value` | file/text | required | JSONL file or string |
|
|
91
|
+
|
|
92
|
+
### Example JSONL Format
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
{"type":"click","data":{"page":"/home"},"ts":1699900000}
|
|
96
|
+
{"type":"view","data":{"page":"/products"},"ts":1699900001}
|
|
97
|
+
{"type":"click","data":{"page":"/checkout"},"ts":1699900002}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## stream.from_request
|
|
103
|
+
|
|
104
|
+
Stream the incoming HTTP request body for large uploads.
|
|
105
|
+
|
|
106
|
+
```xs
|
|
107
|
+
stream.from_request {
|
|
108
|
+
format = "jsonl"
|
|
109
|
+
} as $record {
|
|
110
|
+
// Process streamed data
|
|
111
|
+
db.add "log" { data = $record }
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Parameters
|
|
116
|
+
|
|
117
|
+
| Parameter | Type | Options | Description |
|
|
118
|
+
|-----------|------|---------|-------------|
|
|
119
|
+
| `format` | text | `jsonl`, `csv`, `raw` | Body format |
|
|
120
|
+
| `headers` | bool | `true` (csv) | CSV has headers |
|
|
121
|
+
| `delimiter` | text | `,` (csv) | CSV delimiter |
|
|
122
|
+
|
|
123
|
+
### Raw Chunks
|
|
124
|
+
|
|
125
|
+
```xs
|
|
126
|
+
stream.from_request {
|
|
127
|
+
format = "raw"
|
|
128
|
+
chunk_size = 8192
|
|
129
|
+
} as $chunk {
|
|
130
|
+
// Process raw bytes
|
|
131
|
+
storage.append_file {
|
|
132
|
+
pathname = "uploads/large_file.bin"
|
|
133
|
+
data = $chunk
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## api.stream
|
|
141
|
+
|
|
142
|
+
Stream response data to the client. Useful for large datasets, real-time feeds, or server-sent events.
|
|
143
|
+
|
|
144
|
+
### Streaming JSONL Response
|
|
145
|
+
|
|
146
|
+
```xs
|
|
147
|
+
query "export_logs" {
|
|
148
|
+
input {
|
|
149
|
+
timestamp start_date
|
|
150
|
+
timestamp end_date
|
|
151
|
+
}
|
|
152
|
+
stack {
|
|
153
|
+
db.query "log" {
|
|
154
|
+
where = $db.log.created_at >= $input.start_date && $db.log.created_at <= $input.end_date
|
|
155
|
+
return = { type: "stream" }
|
|
156
|
+
} as $logs
|
|
157
|
+
|
|
158
|
+
api.stream {
|
|
159
|
+
format = "jsonl"
|
|
160
|
+
value = $logs
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Streaming CSV Response
|
|
167
|
+
|
|
168
|
+
```xs
|
|
169
|
+
query "export_users_csv" {
|
|
170
|
+
stack {
|
|
171
|
+
db.query "user" {
|
|
172
|
+
return = { type: "stream" }
|
|
173
|
+
} as $users
|
|
174
|
+
|
|
175
|
+
api.stream {
|
|
176
|
+
format = "csv"
|
|
177
|
+
value = $users
|
|
178
|
+
headers = ["id", "name", "email", "created_at"]
|
|
179
|
+
filename = "users_export.csv"
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Server-Sent Events (SSE)
|
|
186
|
+
|
|
187
|
+
```xs
|
|
188
|
+
query "live_updates" {
|
|
189
|
+
stack {
|
|
190
|
+
api.stream {
|
|
191
|
+
format = "sse"
|
|
192
|
+
} as $stream
|
|
193
|
+
|
|
194
|
+
// Send events to client
|
|
195
|
+
$stream.send { event = "connected", data = { status: "ok" } }
|
|
196
|
+
|
|
197
|
+
foreach ($updates) {
|
|
198
|
+
each as $update {
|
|
199
|
+
$stream.send { event = "update", data = $update }
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
$stream.close
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Parameters
|
|
209
|
+
|
|
210
|
+
| Parameter | Type | Options | Description |
|
|
211
|
+
|-----------|------|---------|-------------|
|
|
212
|
+
| `format` | text | `jsonl`, `csv`, `sse`, `raw` | Stream format |
|
|
213
|
+
| `value` | stream | optional | Data source for jsonl/csv |
|
|
214
|
+
| `headers` | text[] | optional | CSV column headers |
|
|
215
|
+
| `filename` | text | optional | Suggested download filename |
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## Streaming Patterns
|
|
220
|
+
|
|
221
|
+
### Large File Import
|
|
222
|
+
|
|
223
|
+
```xs
|
|
224
|
+
function "import_large_csv" {
|
|
225
|
+
input {
|
|
226
|
+
file csv_file
|
|
227
|
+
}
|
|
228
|
+
stack {
|
|
229
|
+
var $processed { value = 0 }
|
|
230
|
+
var $errors { value = [] }
|
|
231
|
+
|
|
232
|
+
stream.from_csv {
|
|
233
|
+
value = $input.csv_file
|
|
234
|
+
headers = true
|
|
235
|
+
} as $row {
|
|
236
|
+
try_catch {
|
|
237
|
+
try {
|
|
238
|
+
db.add "record" {
|
|
239
|
+
data = {
|
|
240
|
+
name: $row.name|trim,
|
|
241
|
+
email: $row.email|trim|lower,
|
|
242
|
+
created_at: now
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
math.add $processed { value = 1 }
|
|
246
|
+
}
|
|
247
|
+
catch {
|
|
248
|
+
var.update $errors {
|
|
249
|
+
value = $errors|push:{ row: $processed, error: $error.message }
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
response = { processed: $processed, errors: $errors }
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### ETL Pipeline
|
|
260
|
+
|
|
261
|
+
```xs
|
|
262
|
+
function "etl_events" {
|
|
263
|
+
input {
|
|
264
|
+
file events_file
|
|
265
|
+
}
|
|
266
|
+
stack {
|
|
267
|
+
stream.from_jsonl {
|
|
268
|
+
value = $input.events_file
|
|
269
|
+
} as $event {
|
|
270
|
+
// Transform
|
|
271
|
+
var $transformed {
|
|
272
|
+
value = {
|
|
273
|
+
event_type: $event.type|to_lower,
|
|
274
|
+
user_id: $event.user_id|to_int,
|
|
275
|
+
metadata: $event.data|json_encode,
|
|
276
|
+
occurred_at: $event.timestamp|to_timestamp
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Load
|
|
281
|
+
db.add "processed_event" {
|
|
282
|
+
data = $transformed
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
response = { status: "complete" }
|
|
287
|
+
}
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### Chunked Export
|
|
291
|
+
|
|
292
|
+
```xs
|
|
293
|
+
query "stream_large_dataset" {
|
|
294
|
+
stack {
|
|
295
|
+
// Stream query results directly to response
|
|
296
|
+
db.query "analytics" {
|
|
297
|
+
where = $db.analytics.created_at >= $input.since
|
|
298
|
+
sort = { created_at: "asc" }
|
|
299
|
+
return = { type: "stream", chunk_size: 1000 }
|
|
300
|
+
} as $data
|
|
301
|
+
|
|
302
|
+
api.stream {
|
|
303
|
+
format = "jsonl"
|
|
304
|
+
value = $data
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
---
|
|
311
|
+
|
|
312
|
+
## Best Practices
|
|
313
|
+
|
|
314
|
+
1. **Use streaming for large files** - Prevents memory exhaustion
|
|
315
|
+
2. **Process in batches** - Commit database operations periodically
|
|
316
|
+
3. **Handle errors gracefully** - Log failures without stopping stream
|
|
317
|
+
4. **Set appropriate chunk sizes** - Balance memory and performance
|
|
318
|
+
5. **Use JSONL for structured data** - Easier to parse than multi-line JSON
|
|
@@ -382,3 +382,270 @@ conditional {
|
|
|
382
382
|
}
|
|
383
383
|
}
|
|
384
384
|
```
|
|
385
|
+
|
|
386
|
+
---
|
|
387
|
+
|
|
388
|
+
## System Variables
|
|
389
|
+
|
|
390
|
+
Built-in variables available in the execution context.
|
|
391
|
+
|
|
392
|
+
### Request Context
|
|
393
|
+
|
|
394
|
+
| Variable | Description |
|
|
395
|
+
|----------|-------------|
|
|
396
|
+
| `$remote_ip` | Client IP address |
|
|
397
|
+
| `$remote_port` | Client port number |
|
|
398
|
+
| `$remote_host` | Remote hostname |
|
|
399
|
+
| `$request_method` | HTTP method (GET, POST, etc.) |
|
|
400
|
+
| `$request_uri` | Full request URI |
|
|
401
|
+
| `$request_querystring` | Query string portion |
|
|
402
|
+
| `$http_headers` | Request headers object |
|
|
403
|
+
| `$request_auth_token` | Authorization token (if present) |
|
|
404
|
+
|
|
405
|
+
### System Context
|
|
406
|
+
|
|
407
|
+
| Variable | Description |
|
|
408
|
+
|----------|-------------|
|
|
409
|
+
| `$datasource` | Current data source name |
|
|
410
|
+
| `$branch` | Current branch name |
|
|
411
|
+
| `$tenant` | Tenant ID (multi-tenant apps) |
|
|
412
|
+
| `$api_baseurl` | API base URL |
|
|
413
|
+
| `$webflow` | Webflow context (if applicable) |
|
|
414
|
+
|
|
415
|
+
### Access via $env
|
|
416
|
+
|
|
417
|
+
```xs
|
|
418
|
+
// Request variables accessed through $env
|
|
419
|
+
var $client_ip { value = $env.$remote_ip }
|
|
420
|
+
var $method { value = $env.$request_method }
|
|
421
|
+
var $headers { value = $env.$http_headers }
|
|
422
|
+
var $current_branch { value = $env.$branch }
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
---
|
|
426
|
+
|
|
427
|
+
## Additional Operators
|
|
428
|
+
|
|
429
|
+
### Nullish Coalescing
|
|
430
|
+
|
|
431
|
+
Return right operand when left is null (not just falsy):
|
|
432
|
+
|
|
433
|
+
```xs
|
|
434
|
+
$value ?? "default" // Returns "default" only if $value is null
|
|
435
|
+
$value || "default" // Returns "default" if $value is null, 0, "", or false
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
```xs
|
|
439
|
+
// Difference example
|
|
440
|
+
var $count { value = 0 }
|
|
441
|
+
$count ?? 10 // Returns 0 (not null)
|
|
442
|
+
$count || 10 // Returns 10 (0 is falsy)
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
### Database Filter Operators
|
|
446
|
+
|
|
447
|
+
Additional operators for `db.query` where clauses:
|
|
448
|
+
|
|
449
|
+
| Operator | Description | Example |
|
|
450
|
+
|----------|-------------|---------|
|
|
451
|
+
| `@>` | JSON contains | `$db.meta @> {"type": "featured"}` |
|
|
452
|
+
| `~` | Regex match | `$db.name ~ "^test"` |
|
|
453
|
+
| `!~` | Regex not match | `$db.name !~ "^draft"` |
|
|
454
|
+
| `not in` | Not in list | `$db.status not in ["deleted", "hidden"]` |
|
|
455
|
+
| `not between` | Not in range | `$db.price not between 0:10` |
|
|
456
|
+
| `not contains` | Array not contains | `$db.tags not contains "spam"` |
|
|
457
|
+
| `not includes` | String not includes | `$db.title not includes "test"` |
|
|
458
|
+
| `not overlaps` | Arrays don't overlap | `$db.tags not overlaps ["hidden", "draft"]` |
|
|
459
|
+
| `not ilike` | Case-insensitive not like | `$db.name not ilike "%test%"` |
|
|
460
|
+
|
|
461
|
+
```xs
|
|
462
|
+
db.query "product" {
|
|
463
|
+
where = $db.product.status not in ["deleted", "archived"]
|
|
464
|
+
&& $db.product.metadata @> {"featured": true}
|
|
465
|
+
&& $db.product.sku ~ "^SKU-[0-9]+"
|
|
466
|
+
} as $products
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
---
|
|
470
|
+
|
|
471
|
+
## Additional Filters
|
|
472
|
+
|
|
473
|
+
### Text Domain Functions
|
|
474
|
+
|
|
475
|
+
Functional equivalents for string operations:
|
|
476
|
+
|
|
477
|
+
```xs
|
|
478
|
+
text.contains("hello world", "world") // true
|
|
479
|
+
text.starts_with("hello", "he") // true
|
|
480
|
+
text.ends_with("hello", "lo") // true
|
|
481
|
+
text.icontains("Hello World", "WORLD") // true (case-insensitive)
|
|
482
|
+
text.istarts_with("Hello", "HE") // true
|
|
483
|
+
text.iends_with("Hello", "LO") // true
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
### Object Domain Functions
|
|
487
|
+
|
|
488
|
+
Functional equivalents for object operations:
|
|
489
|
+
|
|
490
|
+
```xs
|
|
491
|
+
object.keys({a: 1, b: 2}) // ["a", "b"]
|
|
492
|
+
object.values({a: 1, b: 2}) // [1, 2]
|
|
493
|
+
object.entries({a: 1, b: 2}) // [{key: "a", value: 1}, {key: "b", value: 2}]
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
### Math Domain Functions
|
|
497
|
+
|
|
498
|
+
Functional equivalents for math operations:
|
|
499
|
+
|
|
500
|
+
```xs
|
|
501
|
+
math.add(5, 3) // 8
|
|
502
|
+
math.sub(10, 4) // 6
|
|
503
|
+
math.mul(3, 4) // 12
|
|
504
|
+
math.div(20, 5) // 4
|
|
505
|
+
math.mod(10, 3) // 1
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
### Bitwise Operations
|
|
509
|
+
|
|
510
|
+
```xs
|
|
511
|
+
// As filters
|
|
512
|
+
5|bitwise_and:3 // 1
|
|
513
|
+
5|bitwise_or:3 // 7
|
|
514
|
+
5|bitwise_xor:3 // 6
|
|
515
|
+
5|bitwise_not // -6
|
|
516
|
+
|
|
517
|
+
// As functions
|
|
518
|
+
math.bitwise.and(5, 3) // 1
|
|
519
|
+
math.bitwise.or(5, 3) // 7
|
|
520
|
+
math.bitwise.xor(5, 3) // 6
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
### Logical NOT Filter
|
|
524
|
+
|
|
525
|
+
```xs
|
|
526
|
+
true|not // false
|
|
527
|
+
false|not // true
|
|
528
|
+
$condition|not // Inverts boolean
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
### Array Filtering
|
|
532
|
+
|
|
533
|
+
| Filter | Description | Example |
|
|
534
|
+
|--------|-------------|---------|
|
|
535
|
+
| `filter_empty` | Remove empty values | `$arr\|filter_empty` |
|
|
536
|
+
| `filter_empty_text` | Remove empty strings | `$arr\|filter_empty_text` |
|
|
537
|
+
| `filter_empty_array` | Remove empty arrays | `$arr\|filter_empty_array` |
|
|
538
|
+
| `filter_empty_object` | Remove empty objects | `$arr\|filter_empty_object` |
|
|
539
|
+
| `filter_null` | Remove null values | `$arr\|filter_null` |
|
|
540
|
+
| `filter_zero` | Remove zero values | `$arr\|filter_zero` |
|
|
541
|
+
| `filter_false` | Remove false values | `$arr\|filter_false` |
|
|
542
|
+
|
|
543
|
+
```xs
|
|
544
|
+
[1, null, "", 0, "text", false]|filter_empty // [1, "text"]
|
|
545
|
+
["a", "", "b", ""]|filter_empty_text // ["a", "b"]
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
### Array Fill Operations
|
|
549
|
+
|
|
550
|
+
```xs
|
|
551
|
+
|fill:5:"x" // ["x", "x", "x", "x", "x"]
|
|
552
|
+
["a", "b"]|fill_keys:{"a": 1, "b": 2} // {a: 1, b: 2}
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
### Deep Merge & Comparison
|
|
556
|
+
|
|
557
|
+
```xs
|
|
558
|
+
{a: {b: 1}}|merge_recursive:{a: {c: 2}} // {a: {b: 1, c: 2}}
|
|
559
|
+
[1, 2, 3]|diff_assoc:[2] // Associative diff
|
|
560
|
+
[1, 2, 3]|intersect_assoc:[2, 3, 4] // Associative intersect
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
### Encoding Filters
|
|
564
|
+
|
|
565
|
+
| Filter | Description | Example |
|
|
566
|
+
|--------|-------------|---------|
|
|
567
|
+
| `list_encodings` | List available encodings | `\|list_encodings` |
|
|
568
|
+
| `detect_encoding` | Detect string encoding | `$text\|detect_encoding` |
|
|
569
|
+
| `to_utf8` | Convert to UTF-8 | `$text\|to_utf8` |
|
|
570
|
+
| `from_utf8` | Convert from UTF-8 | `$text\|from_utf8:"ISO-8859-1"` |
|
|
571
|
+
| `convert_encoding` | Convert encodings | `$text\|convert_encoding:"UTF-8":"ISO-8859-1"` |
|
|
572
|
+
|
|
573
|
+
```xs
|
|
574
|
+
// CSV parsing (alternative to csv_decode)
|
|
575
|
+
$csv_text|csv_parse // Parse CSV string
|
|
576
|
+
$data|csv_create // Create CSV string
|
|
577
|
+
|
|
578
|
+
// Query string
|
|
579
|
+
"a=1&b=2"|querystring_parse // {a: "1", b: "2"}
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
### String Escape Filters
|
|
583
|
+
|
|
584
|
+
| Filter | Description |
|
|
585
|
+
|--------|-------------|
|
|
586
|
+
| `addslashes` | Escape quotes and backslashes |
|
|
587
|
+
| `escape` | HTML escape |
|
|
588
|
+
| `text_escape` | Escape for text output |
|
|
589
|
+
| `text_unescape` | Unescape text |
|
|
590
|
+
| `regex_quote` | Escape regex special characters |
|
|
591
|
+
|
|
592
|
+
```xs
|
|
593
|
+
"Hello \"World\""|addslashes // "Hello \\\"World\\\""
|
|
594
|
+
"<script>"|escape // "<script>"
|
|
595
|
+
"^test$"|regex_quote // "\^test\$"
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
### Trigonometry Examples
|
|
599
|
+
|
|
600
|
+
```xs
|
|
601
|
+
// Radians and degrees
|
|
602
|
+
90|deg2rad // 1.5707963...
|
|
603
|
+
1.5707963|rad2deg // 90
|
|
604
|
+
|
|
605
|
+
// Trig functions (input in radians)
|
|
606
|
+
0|sin // 0
|
|
607
|
+
0|cos // 1
|
|
608
|
+
0.785398|tan // ~1 (45 degrees)
|
|
609
|
+
|
|
610
|
+
// Inverse trig
|
|
611
|
+
0|asin // 0
|
|
612
|
+
1|acos // 0
|
|
613
|
+
1|atan // 0.785398...
|
|
614
|
+
|
|
615
|
+
// Hyperbolic
|
|
616
|
+
0|sinh // 0
|
|
617
|
+
0|cosh // 1
|
|
618
|
+
0|tanh // 0
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
### DB Query Timestamp Filters
|
|
622
|
+
|
|
623
|
+
Extended timestamp operations for database queries:
|
|
624
|
+
|
|
625
|
+
```xs
|
|
626
|
+
$db.created_at|timestamp_year // Extract year
|
|
627
|
+
$db.created_at|timestamp_month // Extract month (1-12)
|
|
628
|
+
$db.created_at|timestamp_week // Extract week number
|
|
629
|
+
$db.created_at|timestamp_day_of_month // Day of month (1-31)
|
|
630
|
+
$db.created_at|timestamp_day_of_week // Day of week (0-6)
|
|
631
|
+
$db.created_at|timestamp_day_of_year // Day of year (1-366)
|
|
632
|
+
$db.created_at|timestamp_hour // Hour (0-23)
|
|
633
|
+
$db.created_at|timestamp_minute // Minute (0-59)
|
|
634
|
+
|
|
635
|
+
// Epoch variants
|
|
636
|
+
$db.created_at|timestamp_epoch_seconds // Seconds since epoch
|
|
637
|
+
$db.created_at|timestamp_epoch_ms // Milliseconds since epoch
|
|
638
|
+
```
|
|
639
|
+
|
|
640
|
+
### Vector Operations (AI/ML)
|
|
641
|
+
|
|
642
|
+
Additional vector similarity functions:
|
|
643
|
+
|
|
644
|
+
```xs
|
|
645
|
+
$db.embedding|l1_distance_manhattan:$input.vector // L1/Manhattan distance
|
|
646
|
+
$db.embedding|negative_inner_product:$input.vector // Negative inner product
|
|
647
|
+
$db.embedding|inner_product:$input.vector // Inner product
|
|
648
|
+
|
|
649
|
+
// Geo covers (for polygon containment)
|
|
650
|
+
$db.boundary|covers:$input.point // Polygon covers point
|
|
651
|
+
```
|
package/xanoscript_docs/types.md
CHANGED
|
@@ -176,35 +176,80 @@ geo_multipoint points
|
|
|
176
176
|
Filters validate and transform input values. Chain with `|`.
|
|
177
177
|
|
|
178
178
|
### String Filters
|
|
179
|
-
| Filter | Description |
|
|
180
|
-
|
|
181
|
-
| `trim` | Remove leading/trailing whitespace |
|
|
182
|
-
| `lower` | Convert to lowercase |
|
|
183
|
-
| `upper` | Convert to uppercase |
|
|
184
|
-
| `min:<n>` | Minimum length |
|
|
185
|
-
| `max:<n>` | Maximum length |
|
|
186
|
-
| `ok:<chars>` | Allow only specified characters |
|
|
187
|
-
| `prevent:<str>` | Block specific substrings |
|
|
188
|
-
| `startsWith:<prefix>` | Require prefix |
|
|
189
|
-
| `
|
|
190
|
-
| `
|
|
179
|
+
| Filter | Description | Example |
|
|
180
|
+
|--------|-------------|---------|
|
|
181
|
+
| `trim` | Remove leading/trailing whitespace | `text name filters=trim` |
|
|
182
|
+
| `lower` | Convert to lowercase | `text email filters=lower` |
|
|
183
|
+
| `upper` | Convert to uppercase | `text code filters=upper` |
|
|
184
|
+
| `min:<n>` | Minimum length | `text name filters=min:2` |
|
|
185
|
+
| `max:<n>` | Maximum length | `text bio filters=max:500` |
|
|
186
|
+
| `ok:<chars>` | Allow only specified characters | `text hex filters=ok:0123456789abcdef` |
|
|
187
|
+
| `prevent:<str>` | Block specific substrings | `text name filters=prevent:admin` |
|
|
188
|
+
| `startsWith:<prefix>` | Require prefix | `text sku filters=startsWith:SKU-` |
|
|
189
|
+
| `endsWith:<suffix>` | Require suffix | `text file filters=endsWith:.pdf` |
|
|
190
|
+
| `alphaOk` | Allow only letters (a-zA-Z) | `text name filters=alphaOk` |
|
|
191
|
+
| `digitOk` | Allow only digits (0-9) | `text code filters=digitOk` |
|
|
192
|
+
| `alphaNumOk` | Allow letters and digits | `text username filters=alphaNumOk` |
|
|
193
|
+
| `pattern:<regex>` | Match regex pattern | `text phone filters=pattern:^\+?[0-9]+$` |
|
|
191
194
|
|
|
192
195
|
### Numeric Filters
|
|
193
|
-
| Filter | Description |
|
|
194
|
-
|
|
195
|
-
| `min:<n>` | Minimum value |
|
|
196
|
-
| `max:<n>` | Maximum value |
|
|
196
|
+
| Filter | Description | Example |
|
|
197
|
+
|--------|-------------|---------|
|
|
198
|
+
| `min:<n>` | Minimum value | `int age filters=min:0` |
|
|
199
|
+
| `max:<n>` | Maximum value | `int age filters=max:150` |
|
|
200
|
+
| `between:<a>:<b>` | Value between a and b | `int score filters=between:0:100` |
|
|
201
|
+
|
|
202
|
+
### Array Filters
|
|
203
|
+
| Filter | Description | Example |
|
|
204
|
+
|--------|-------------|---------|
|
|
205
|
+
| `min:<n>` | Minimum array length | `text[] tags filters=min:1` |
|
|
206
|
+
| `max:<n>` | Maximum array length | `text[] tags filters=max:10` |
|
|
207
|
+
| `unique` | Remove duplicates | `int[] ids filters=unique` |
|
|
208
|
+
|
|
209
|
+
### Character Set Filters
|
|
197
210
|
|
|
198
|
-
### Examples
|
|
199
211
|
```xs
|
|
200
212
|
input {
|
|
201
|
-
|
|
213
|
+
// Allow only specific characters
|
|
214
|
+
text hex_code filters=ok:0123456789abcdef
|
|
215
|
+
|
|
216
|
+
// Allow letters only
|
|
217
|
+
text name filters=alphaOk
|
|
218
|
+
|
|
219
|
+
// Allow digits only
|
|
220
|
+
text pin filters=digitOk
|
|
221
|
+
|
|
222
|
+
// Combine: letters, digits, and underscore
|
|
223
|
+
text username filters=ok:abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Pattern Validation
|
|
228
|
+
|
|
229
|
+
```xs
|
|
230
|
+
input {
|
|
231
|
+
// Phone number pattern
|
|
232
|
+
text phone filters=pattern:^\+?[1-9]\d{1,14}$
|
|
233
|
+
|
|
234
|
+
// Postal code pattern
|
|
235
|
+
text zip filters=pattern:^\d{5}(-\d{4})?$
|
|
236
|
+
|
|
237
|
+
// Custom ID format
|
|
238
|
+
text product_id filters=pattern:^[A-Z]{2}-\d{4}$
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### Combined Examples
|
|
243
|
+
```xs
|
|
244
|
+
input {
|
|
245
|
+
text username filters=trim|lower|min:3|max:20|alphaNumOk
|
|
202
246
|
email contact filters=trim|lower
|
|
203
247
|
int age filters=min:0|max:150
|
|
204
|
-
text hex_code filters=ok:abcdef0123456789
|
|
205
|
-
text[] tags filters=trim|lower|max:50
|
|
248
|
+
text hex_code filters=ok:abcdef0123456789|min:6|max:6
|
|
249
|
+
text[] tags filters=trim|lower|max:50|unique
|
|
250
|
+
text phone filters=trim|pattern:^\+?[0-9\s-]+$
|
|
251
|
+
int quantity filters=min:1|max:100
|
|
206
252
|
}
|
|
207
|
-
```
|
|
208
253
|
|
|
209
254
|
---
|
|
210
255
|
|