@xano/developer-mcp 1.0.26 → 1.0.28
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 +1 -1
- package/dist/meta_api_docs/topics/workspace.js +45 -2
- package/dist/xanoscript_docs/README.md +71 -67
- package/dist/xanoscript_docs/apis.md +81 -27
- package/dist/xanoscript_docs/branch.md +13 -13
- package/dist/xanoscript_docs/database.md +57 -17
- package/dist/xanoscript_docs/functions.md +29 -78
- package/dist/xanoscript_docs/integrations.md +0 -10
- package/dist/xanoscript_docs/performance.md +15 -33
- package/dist/xanoscript_docs/realtime.md +1 -48
- package/dist/xanoscript_docs/security.md +2 -0
- package/dist/xanoscript_docs/tables.md +47 -1
- package/dist/xanoscript_docs/tools.md +2 -19
- package/dist/xanoscript_docs/triggers.md +2 -27
- package/dist/xanoscript_docs/types.md +12 -10
- package/package.json +1 -1
|
@@ -8,17 +8,17 @@ Complete reference for XanoScript database operations.
|
|
|
8
8
|
|
|
9
9
|
## Quick Reference
|
|
10
10
|
|
|
11
|
-
| Operation
|
|
12
|
-
|
|
13
|
-
| `db.query`
|
|
14
|
-
| `db.get`
|
|
15
|
-
| `db.has`
|
|
16
|
-
| `db.add`
|
|
17
|
-
| `db.edit`
|
|
18
|
-
| `db.patch`
|
|
19
|
-
| `db.add_or_edit` | Upsert record
|
|
20
|
-
| `db.del`
|
|
21
|
-
| `db.truncate`
|
|
11
|
+
| Operation | Purpose | Returns |
|
|
12
|
+
| ---------------- | ----------------------------- | ------------------------ |
|
|
13
|
+
| `db.query` | Query multiple records | List/single/count/exists |
|
|
14
|
+
| `db.get` | Get single record by field | Record or null |
|
|
15
|
+
| `db.has` | Check if record exists | Boolean |
|
|
16
|
+
| `db.add` | Insert new record | Created record |
|
|
17
|
+
| `db.edit` | Update record (inline data) | Updated record |
|
|
18
|
+
| `db.patch` | Update record (variable data) | Updated record |
|
|
19
|
+
| `db.add_or_edit` | Upsert record | Record |
|
|
20
|
+
| `db.del` | Delete record | None |
|
|
21
|
+
| `db.truncate` | Delete all records | None |
|
|
22
22
|
|
|
23
23
|
---
|
|
24
24
|
|
|
@@ -27,6 +27,7 @@ Complete reference for XanoScript database operations.
|
|
|
27
27
|
Query multiple records with filters, sorting, and pagination.
|
|
28
28
|
|
|
29
29
|
### Basic Query
|
|
30
|
+
|
|
30
31
|
```xs
|
|
31
32
|
db.query "product" {
|
|
32
33
|
where = $db.product.is_active == true
|
|
@@ -34,6 +35,7 @@ db.query "product" {
|
|
|
34
35
|
```
|
|
35
36
|
|
|
36
37
|
### Where Operators
|
|
38
|
+
|
|
37
39
|
```xs
|
|
38
40
|
// Comparison
|
|
39
41
|
$db.product.price == 100
|
|
@@ -62,13 +64,14 @@ $db.product.category == "electronics" || $db.product.featured == true
|
|
|
62
64
|
```
|
|
63
65
|
|
|
64
66
|
### Return Types
|
|
67
|
+
|
|
65
68
|
```xs
|
|
66
|
-
//
|
|
69
|
+
// returns an array of products (default)
|
|
67
70
|
db.query "product" {
|
|
68
71
|
return = { type: "list" }
|
|
69
72
|
} as $products
|
|
70
73
|
|
|
71
|
-
//
|
|
74
|
+
// Returns a paginated list of products
|
|
72
75
|
db.query "product" {
|
|
73
76
|
return = {
|
|
74
77
|
type: "list",
|
|
@@ -76,19 +79,19 @@ db.query "product" {
|
|
|
76
79
|
}
|
|
77
80
|
} as $products
|
|
78
81
|
|
|
79
|
-
//
|
|
82
|
+
// Returns a single record
|
|
80
83
|
db.query "product" {
|
|
81
84
|
where = $db.product.sku == $input.sku
|
|
82
85
|
return = { type: "single" }
|
|
83
86
|
} as $product
|
|
84
87
|
|
|
85
|
-
//
|
|
88
|
+
// Returns a count (number)
|
|
86
89
|
db.query "product" {
|
|
87
90
|
where = $db.product.is_active == true
|
|
88
91
|
return = { type: "count" }
|
|
89
92
|
} as $count
|
|
90
93
|
|
|
91
|
-
//
|
|
94
|
+
// Returns a boolean indicating existence
|
|
92
95
|
db.query "product" {
|
|
93
96
|
where = $db.product.email == $input.email
|
|
94
97
|
return = { type: "exists" }
|
|
@@ -96,6 +99,7 @@ db.query "product" {
|
|
|
96
99
|
```
|
|
97
100
|
|
|
98
101
|
### Sorting
|
|
102
|
+
|
|
99
103
|
```xs
|
|
100
104
|
db.query "product" {
|
|
101
105
|
sort = { created_at: "desc" } // Descending
|
|
@@ -105,6 +109,7 @@ db.query "product" {
|
|
|
105
109
|
```
|
|
106
110
|
|
|
107
111
|
### Joins
|
|
112
|
+
|
|
108
113
|
```xs
|
|
109
114
|
db.query "comment" {
|
|
110
115
|
join = {
|
|
@@ -114,11 +119,15 @@ db.query "comment" {
|
|
|
114
119
|
where: $db.comment.post_id == $db.post.id
|
|
115
120
|
}
|
|
116
121
|
}
|
|
122
|
+
eval = {
|
|
123
|
+
post_title: $db.post.title
|
|
124
|
+
}
|
|
117
125
|
where = $db.post.author_id == $auth.id
|
|
118
126
|
} as $comments
|
|
119
127
|
```
|
|
120
128
|
|
|
121
129
|
### Eval (Computed Fields)
|
|
130
|
+
|
|
122
131
|
```xs
|
|
123
132
|
db.query "order" {
|
|
124
133
|
join = {
|
|
@@ -132,6 +141,7 @@ db.query "order" {
|
|
|
132
141
|
```
|
|
133
142
|
|
|
134
143
|
### Addons (Related Data)
|
|
144
|
+
|
|
135
145
|
```xs
|
|
136
146
|
db.query "post" {
|
|
137
147
|
where = $db.post.author_id == $auth.id
|
|
@@ -141,6 +151,30 @@ db.query "post" {
|
|
|
141
151
|
} as $posts
|
|
142
152
|
```
|
|
143
153
|
|
|
154
|
+
### Vector Search (Similarity)
|
|
155
|
+
|
|
156
|
+
Search by vector similarity using embeddings. Requires a `vector` column with a `vector` index on the table (see [tables.md](tables.md)).
|
|
157
|
+
|
|
158
|
+
```xs
|
|
159
|
+
// Embeddings from an LLM engine
|
|
160
|
+
var $embeddings {
|
|
161
|
+
value = [0.345, 0.1553, ...]
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
db.query agent_message {
|
|
165
|
+
sort = {distance: "asc"}
|
|
166
|
+
eval = {
|
|
167
|
+
distance: $db.agent_message.embeddings|cosine_distance:$embeddings
|
|
168
|
+
}
|
|
169
|
+
return = {
|
|
170
|
+
type : "list"
|
|
171
|
+
paging: {page: 1, per_page: 5, metadata: false}
|
|
172
|
+
}
|
|
173
|
+
} as $search_results
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
The `cosine_distance` filter computes the distance between the row's vector and the provided embeddings. Sort by `distance` ascending (smallest distance = most similar) — this ordering is required to leverage the PostgreSQL vector index.
|
|
177
|
+
|
|
144
178
|
---
|
|
145
179
|
|
|
146
180
|
## db.get
|
|
@@ -338,6 +372,7 @@ db.transaction {
|
|
|
338
372
|
Filters for use in `where` clauses:
|
|
339
373
|
|
|
340
374
|
### String/Text
|
|
375
|
+
|
|
341
376
|
```xs
|
|
342
377
|
$db.name|to_lower // Case conversion
|
|
343
378
|
$db.name|concat:" " // Concatenation
|
|
@@ -345,6 +380,7 @@ $db.text|substr:0:100 // Substring
|
|
|
345
380
|
```
|
|
346
381
|
|
|
347
382
|
### Numeric
|
|
383
|
+
|
|
348
384
|
```xs
|
|
349
385
|
$db.price|round:2
|
|
350
386
|
$db.price|floor
|
|
@@ -354,6 +390,7 @@ $db.price|mul:1.1
|
|
|
354
390
|
```
|
|
355
391
|
|
|
356
392
|
### Timestamp
|
|
393
|
+
|
|
357
394
|
```xs
|
|
358
395
|
$db.created_at|timestamp_year
|
|
359
396
|
$db.created_at|timestamp_month
|
|
@@ -362,18 +399,21 @@ $db.created_at|timestamp_subtract_hours:24
|
|
|
362
399
|
```
|
|
363
400
|
|
|
364
401
|
### Geographic
|
|
402
|
+
|
|
365
403
|
```xs
|
|
366
404
|
$db.location|distance:$input.point // Distance in meters
|
|
367
405
|
$db.location|within:$input.point:1000 // Within radius
|
|
368
406
|
```
|
|
369
407
|
|
|
370
408
|
### Vector (AI/ML)
|
|
409
|
+
|
|
371
410
|
```xs
|
|
372
|
-
$db.embedding|
|
|
411
|
+
$db.embedding|cosine_distance:$input.vector
|
|
373
412
|
$db.embedding|l2_distance_euclidean:$input.vector
|
|
374
413
|
```
|
|
375
414
|
|
|
376
415
|
### Full-Text Search
|
|
416
|
+
|
|
377
417
|
```xs
|
|
378
418
|
$db.content|search_rank:$input.query
|
|
379
419
|
```
|
|
@@ -19,7 +19,9 @@ function "<name>" {
|
|
|
19
19
|
}
|
|
20
20
|
response = $result
|
|
21
21
|
}
|
|
22
|
+
```
|
|
22
23
|
|
|
24
|
+
```xs
|
|
23
25
|
// Function with no inputs - IMPORTANT: braces must be on separate lines
|
|
24
26
|
function "<name>" {
|
|
25
27
|
description = "..."
|
|
@@ -31,6 +33,7 @@ function "<name>" {
|
|
|
31
33
|
```
|
|
32
34
|
|
|
33
35
|
### Calling Functions
|
|
36
|
+
|
|
34
37
|
```xs
|
|
35
38
|
function.run "<name>" {
|
|
36
39
|
input = { key: value }
|
|
@@ -55,7 +58,9 @@ function "calculate_total" {
|
|
|
55
58
|
```
|
|
56
59
|
|
|
57
60
|
### With Subfolders
|
|
61
|
+
|
|
58
62
|
Functions can be organized in subfolders:
|
|
63
|
+
|
|
59
64
|
```
|
|
60
65
|
functions/
|
|
61
66
|
├── math/
|
|
@@ -82,33 +87,6 @@ input {
|
|
|
82
87
|
}
|
|
83
88
|
```
|
|
84
89
|
|
|
85
|
-
### Empty Input Blocks
|
|
86
|
-
|
|
87
|
-
**CRITICAL:** When a function has no input parameters, the input block braces MUST be on separate lines. This is a syntax requirement.
|
|
88
|
-
|
|
89
|
-
```xs
|
|
90
|
-
// CORRECT - braces on separate lines
|
|
91
|
-
function "get_all_users" {
|
|
92
|
-
description = "Returns all users"
|
|
93
|
-
input {
|
|
94
|
-
}
|
|
95
|
-
stack {
|
|
96
|
-
db.query "user" {} as $users
|
|
97
|
-
}
|
|
98
|
-
response = $users
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// WRONG - will cause parsing errors
|
|
102
|
-
function "get_all_users" {
|
|
103
|
-
description = "Returns all users"
|
|
104
|
-
input {} // <-- ERROR: braces must be on separate lines
|
|
105
|
-
stack {
|
|
106
|
-
db.query "user" {} as $users
|
|
107
|
-
}
|
|
108
|
-
response = $users
|
|
109
|
-
}
|
|
110
|
-
```
|
|
111
|
-
|
|
112
90
|
---
|
|
113
91
|
|
|
114
92
|
## Stack Block
|
|
@@ -116,6 +94,7 @@ function "get_all_users" {
|
|
|
116
94
|
Contains the function logic using control flow, variables, and operations.
|
|
117
95
|
|
|
118
96
|
### Variables
|
|
97
|
+
|
|
119
98
|
```xs
|
|
120
99
|
stack {
|
|
121
100
|
var $counter { value = 0 }
|
|
@@ -127,6 +106,7 @@ stack {
|
|
|
127
106
|
```
|
|
128
107
|
|
|
129
108
|
### Conditionals
|
|
109
|
+
|
|
130
110
|
```xs
|
|
131
111
|
stack {
|
|
132
112
|
conditional {
|
|
@@ -144,6 +124,7 @@ stack {
|
|
|
144
124
|
```
|
|
145
125
|
|
|
146
126
|
### Loops
|
|
127
|
+
|
|
147
128
|
```xs
|
|
148
129
|
stack {
|
|
149
130
|
// For loop (count-based)
|
|
@@ -170,6 +151,7 @@ stack {
|
|
|
170
151
|
```
|
|
171
152
|
|
|
172
153
|
### Switch
|
|
154
|
+
|
|
173
155
|
```xs
|
|
174
156
|
stack {
|
|
175
157
|
switch ($input.status) {
|
|
@@ -208,6 +190,7 @@ response = null // No return value
|
|
|
208
190
|
## Calling Functions
|
|
209
191
|
|
|
210
192
|
### Basic Call
|
|
193
|
+
|
|
211
194
|
```xs
|
|
212
195
|
function.run "calculate_total" {
|
|
213
196
|
input = { quantity: 5, price: 10.50 }
|
|
@@ -215,6 +198,7 @@ function.run "calculate_total" {
|
|
|
215
198
|
```
|
|
216
199
|
|
|
217
200
|
### With Variables
|
|
201
|
+
|
|
218
202
|
```xs
|
|
219
203
|
function.run "process_order" {
|
|
220
204
|
input = {
|
|
@@ -226,6 +210,7 @@ function.run "process_order" {
|
|
|
226
210
|
```
|
|
227
211
|
|
|
228
212
|
### Nested Calls
|
|
213
|
+
|
|
229
214
|
```xs
|
|
230
215
|
stack {
|
|
231
216
|
function.run "validate_user" {
|
|
@@ -245,6 +230,7 @@ stack {
|
|
|
245
230
|
## Complete Examples
|
|
246
231
|
|
|
247
232
|
### Utility Function
|
|
233
|
+
|
|
248
234
|
```xs
|
|
249
235
|
function "utils/format_currency" {
|
|
250
236
|
description = "Format number as currency string"
|
|
@@ -265,6 +251,7 @@ function "utils/format_currency" {
|
|
|
265
251
|
```
|
|
266
252
|
|
|
267
253
|
### Data Processing
|
|
254
|
+
|
|
268
255
|
```xs
|
|
269
256
|
function "process_order" {
|
|
270
257
|
input {
|
|
@@ -305,6 +292,7 @@ function "process_order" {
|
|
|
305
292
|
```
|
|
306
293
|
|
|
307
294
|
### Validation Function
|
|
295
|
+
|
|
308
296
|
```xs
|
|
309
297
|
function "validate_email_unique" {
|
|
310
298
|
input {
|
|
@@ -346,65 +334,28 @@ stack {
|
|
|
346
334
|
}
|
|
347
335
|
```
|
|
348
336
|
|
|
349
|
-
### group (
|
|
337
|
+
### group (Organizational Block)
|
|
350
338
|
|
|
351
|
-
|
|
339
|
+
Group related statements together for readability. The `group` block is purely organizational — it does **not** create parallel execution or a new scope.
|
|
352
340
|
|
|
353
341
|
```xs
|
|
354
342
|
stack {
|
|
343
|
+
// Use group to visually organize related initialization
|
|
355
344
|
group {
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
api.request {
|
|
362
|
-
url = "https://api.example.com/products"
|
|
363
|
-
method = "GET"
|
|
364
|
-
} as $products
|
|
365
|
-
|
|
366
|
-
api.request {
|
|
367
|
-
url = "https://api.example.com/orders"
|
|
368
|
-
method = "GET"
|
|
369
|
-
} as $orders
|
|
370
|
-
}
|
|
345
|
+
stack {
|
|
346
|
+
var $total {
|
|
347
|
+
value = 0
|
|
348
|
+
}
|
|
371
349
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
users: $users.response.result,
|
|
376
|
-
products: $products.response.result,
|
|
377
|
-
orders: $orders.response.result
|
|
350
|
+
var $count {
|
|
351
|
+
value = 0
|
|
352
|
+
}
|
|
378
353
|
}
|
|
379
354
|
}
|
|
380
|
-
}
|
|
381
|
-
```
|
|
382
|
-
|
|
383
|
-
### Parallel Database Queries
|
|
384
|
-
|
|
385
|
-
```xs
|
|
386
|
-
stack {
|
|
387
|
-
group {
|
|
388
|
-
db.query "user" {
|
|
389
|
-
where = $db.user.is_active == true
|
|
390
|
-
return = { type: "count" }
|
|
391
|
-
} as $active_users
|
|
392
|
-
|
|
393
|
-
db.query "order" {
|
|
394
|
-
where = $db.order.created_at >= $input.start_date
|
|
395
|
-
return = { type: "count" }
|
|
396
|
-
} as $order_count
|
|
397
|
-
|
|
398
|
-
db.query "product" {
|
|
399
|
-
where = $db.product.stock == 0
|
|
400
|
-
return = { type: "count" }
|
|
401
|
-
} as $out_of_stock
|
|
402
|
-
}
|
|
403
355
|
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
out_of_stock: $out_of_stock
|
|
356
|
+
// Variables from the group are accessible here
|
|
357
|
+
var $average {
|
|
358
|
+
value = $total / $count
|
|
408
359
|
}
|
|
409
360
|
}
|
|
410
361
|
```
|
|
@@ -512,5 +463,5 @@ foreach ($items) {
|
|
|
512
463
|
3. **Organize in folders** - Group related functions: `utils/`, `auth/`, `orders/`
|
|
513
464
|
4. **Return early** - Use return for guard clauses
|
|
514
465
|
5. **Keep stacks shallow** - Avoid deeply nested conditionals
|
|
515
|
-
6. **Use group for
|
|
466
|
+
6. **Use group for organization** - Visually group related statements for readability
|
|
516
467
|
7. **Use remove sparingly** - Consider filtering arrays instead
|
|
@@ -506,16 +506,6 @@ security.check_password {
|
|
|
506
506
|
} as $is_valid
|
|
507
507
|
```
|
|
508
508
|
|
|
509
|
-
### Auth Tokens
|
|
510
|
-
```xs
|
|
511
|
-
security.create_auth_token {
|
|
512
|
-
table = "user"
|
|
513
|
-
id = $user.id
|
|
514
|
-
extras = { role: $user.role }
|
|
515
|
-
expiration = 86400
|
|
516
|
-
} as $token
|
|
517
|
-
```
|
|
518
|
-
|
|
519
509
|
### Encryption
|
|
520
510
|
```xs
|
|
521
511
|
# Encrypt
|
|
@@ -12,7 +12,7 @@ Best practices for building fast, efficient XanoScript applications.
|
|
|
12
12
|
|------|----------------|
|
|
13
13
|
| Database | Indexes, query optimization, pagination |
|
|
14
14
|
| Caching | Redis, response caching |
|
|
15
|
-
| Loops | Bulk operations,
|
|
15
|
+
| Loops | Bulk operations, efficient iteration |
|
|
16
16
|
| Filters | Efficient data transformations |
|
|
17
17
|
|
|
18
18
|
---
|
|
@@ -212,34 +212,25 @@ conditional {
|
|
|
212
212
|
|
|
213
213
|
---
|
|
214
214
|
|
|
215
|
-
##
|
|
215
|
+
## Organizing with Group
|
|
216
216
|
|
|
217
|
-
|
|
217
|
+
The `group` statement is an organizational block for visually grouping related statements. It does **not** create parallel execution or a new scope — variables declared inside a group are accessible outside it.
|
|
218
218
|
|
|
219
219
|
```xs
|
|
220
|
-
//
|
|
220
|
+
// Use group to organize related variable initialization
|
|
221
221
|
group {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
}
|
|
222
|
+
stack {
|
|
223
|
+
var $total {
|
|
224
|
+
value = 0
|
|
225
|
+
}
|
|
226
226
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
products: $product_count
|
|
227
|
+
var $count {
|
|
228
|
+
value = 0
|
|
229
|
+
}
|
|
230
|
+
}
|
|
232
231
|
}
|
|
233
|
-
```
|
|
234
|
-
|
|
235
|
-
### Parallel API Calls
|
|
236
232
|
|
|
237
|
-
|
|
238
|
-
group {
|
|
239
|
-
api.request { url = "https://api1.example.com/data" } as $data1
|
|
240
|
-
api.request { url = "https://api2.example.com/data" } as $data2
|
|
241
|
-
api.request { url = "https://api3.example.com/data" } as $data3
|
|
242
|
-
}
|
|
233
|
+
// $total and $count are accessible here
|
|
243
234
|
```
|
|
244
235
|
|
|
245
236
|
---
|
|
@@ -285,16 +276,7 @@ api.request {
|
|
|
285
276
|
|
|
286
277
|
## Rate Limiting
|
|
287
278
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
```xs
|
|
291
|
-
redis.ratelimit {
|
|
292
|
-
key = "api:" ~ $auth.id
|
|
293
|
-
max = 100
|
|
294
|
-
ttl = 60
|
|
295
|
-
error = "Rate limit exceeded. Try again in 1 minute."
|
|
296
|
-
}
|
|
297
|
-
```
|
|
279
|
+
For basic rate limiting setup, see `xanoscript_docs({ topic: "security" })`. Below are performance-focused patterns.
|
|
298
280
|
|
|
299
281
|
### Tiered Limits
|
|
300
282
|
|
|
@@ -401,7 +383,7 @@ conditional {
|
|
|
401
383
|
4. **Avoid N+1 queries** - Use joins or batch fetching
|
|
402
384
|
5. **Use bulk operations** - For batch inserts/updates
|
|
403
385
|
6. **Cache expensive operations** - Redis with appropriate TTL
|
|
404
|
-
7. **
|
|
386
|
+
7. **Use group for organization** - Group related statements for readability
|
|
405
387
|
8. **Filter early** - In database, not application code
|
|
406
388
|
9. **Stream large responses** - Don't load into memory
|
|
407
389
|
10. **Monitor performance** - Log slow operations
|
|
@@ -261,54 +261,7 @@ api.realtime_event {
|
|
|
261
261
|
|
|
262
262
|
## Realtime Triggers
|
|
263
263
|
|
|
264
|
-
Handle events from connected clients
|
|
265
|
-
|
|
266
|
-
### Basic Realtime Trigger
|
|
267
|
-
|
|
268
|
-
```xs
|
|
269
|
-
realtime_trigger "on_presence" {
|
|
270
|
-
channel = "room:*"
|
|
271
|
-
event = "join"
|
|
272
|
-
stack {
|
|
273
|
-
// $input contains event data
|
|
274
|
-
// $channel contains matched channel
|
|
275
|
-
db.add "presence" {
|
|
276
|
-
data = {
|
|
277
|
-
user_id: $auth.id,
|
|
278
|
-
room_id: $input.room_id,
|
|
279
|
-
joined_at: now
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
// Notify room members
|
|
284
|
-
api.realtime_event {
|
|
285
|
-
channel = $channel
|
|
286
|
-
event = "user_joined"
|
|
287
|
-
data = { user_id: $auth.id }
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
```
|
|
292
|
-
|
|
293
|
-
### Channel Pattern Matching
|
|
294
|
-
|
|
295
|
-
```xs
|
|
296
|
-
realtime_trigger "document_cursor" {
|
|
297
|
-
channel = "document:*" // Wildcard match
|
|
298
|
-
event = "cursor_move"
|
|
299
|
-
stack {
|
|
300
|
-
// Broadcast cursor position to other viewers
|
|
301
|
-
api.realtime_event {
|
|
302
|
-
channel = $channel
|
|
303
|
-
event = "cursor_update"
|
|
304
|
-
data = {
|
|
305
|
-
user_id: $auth.id,
|
|
306
|
-
position: $input.position
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
```
|
|
264
|
+
Handle events from connected clients using `realtime_trigger`. For complete trigger syntax, input schemas, and configuration options, see `xanoscript_docs({ topic: "triggers" })`.
|
|
312
265
|
|
|
313
266
|
---
|
|
314
267
|
|