@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.
@@ -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 // "&lt;script&gt;"
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
+ ```
@@ -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
- | `alphaOk` | Allow only letters |
190
- | `digitOk` | Allow only digits |
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
- text username filters=trim|lower|min:3|max:20|alphaOk
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