@xano/developer-mcp 1.0.7 → 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
+ ```