@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,382 @@
1
+ ---
2
+ applyTo: "functions/**/*.xs, apis/**/*.xs, triggers/**/*.xs"
3
+ ---
4
+
5
+ # Realtime
6
+
7
+ Push real-time updates to connected clients using channels and events.
8
+
9
+ ## Quick Reference
10
+
11
+ | Operation | Purpose |
12
+ |-----------|---------|
13
+ | `api.realtime_event` | Send event to channel |
14
+ | Channel patterns | Organize subscriptions |
15
+ | Realtime triggers | Handle client events |
16
+
17
+ ---
18
+
19
+ ## api.realtime_event
20
+
21
+ Send a real-time event to subscribed clients.
22
+
23
+ ```xs
24
+ api.realtime_event {
25
+ channel = "orders"
26
+ event = "new_order"
27
+ data = {
28
+ order_id: $order.id,
29
+ total: $order.total,
30
+ customer: $order.customer_name
31
+ }
32
+ }
33
+ ```
34
+
35
+ ### Parameters
36
+
37
+ | Parameter | Type | Description |
38
+ |-----------|------|-------------|
39
+ | `channel` | text | Channel name or pattern |
40
+ | `event` | text | Event type name |
41
+ | `data` | any | Payload to send |
42
+
43
+ ---
44
+
45
+ ## Channel Patterns
46
+
47
+ ### Public Channels
48
+
49
+ Available to all authenticated clients.
50
+
51
+ ```xs
52
+ // Global announcements
53
+ api.realtime_event {
54
+ channel = "announcements"
55
+ event = "system_update"
56
+ data = { message: "Maintenance in 10 minutes" }
57
+ }
58
+ ```
59
+
60
+ ### User-Specific Channels
61
+
62
+ Target individual users.
63
+
64
+ ```xs
65
+ // Notify specific user
66
+ api.realtime_event {
67
+ channel = "user:" ~ $user.id
68
+ event = "notification"
69
+ data = {
70
+ title: "New message",
71
+ body: "You have a new message from " ~ $sender.name
72
+ }
73
+ }
74
+ ```
75
+
76
+ ### Resource Channels
77
+
78
+ Updates for specific resources.
79
+
80
+ ```xs
81
+ // Update watchers of a document
82
+ api.realtime_event {
83
+ channel = "document:" ~ $document.id
84
+ event = "content_updated"
85
+ data = {
86
+ updated_by: $auth.id,
87
+ updated_at: now,
88
+ changes: $changes
89
+ }
90
+ }
91
+ ```
92
+
93
+ ### Tenant Channels
94
+
95
+ Multi-tenant isolation.
96
+
97
+ ```xs
98
+ api.realtime_event {
99
+ channel = "tenant:" ~ $env.$tenant ~ ":orders"
100
+ event = "order_created"
101
+ data = $order
102
+ }
103
+ ```
104
+
105
+ ---
106
+
107
+ ## Broadcast Patterns
108
+
109
+ ### To All Connected Users
110
+
111
+ ```xs
112
+ api.realtime_event {
113
+ channel = "global"
114
+ event = "broadcast"
115
+ data = { message: $input.message }
116
+ }
117
+ ```
118
+
119
+ ### To Role-Based Groups
120
+
121
+ ```xs
122
+ // Notify all admins
123
+ foreach ($admin_users) {
124
+ each as $admin {
125
+ api.realtime_event {
126
+ channel = "user:" ~ $admin.id
127
+ event = "admin_alert"
128
+ data = $alert_data
129
+ }
130
+ }
131
+ }
132
+ ```
133
+
134
+ ### To Room/Group
135
+
136
+ ```xs
137
+ api.realtime_event {
138
+ channel = "room:" ~ $input.room_id
139
+ event = "message"
140
+ data = {
141
+ sender_id: $auth.id,
142
+ content: $input.message,
143
+ sent_at: now
144
+ }
145
+ }
146
+ ```
147
+
148
+ ---
149
+
150
+ ## Realtime Triggers
151
+
152
+ Handle events from connected clients.
153
+
154
+ ### Basic Realtime Trigger
155
+
156
+ ```xs
157
+ realtime_trigger "on_presence" {
158
+ channel = "room:*"
159
+ event = "join"
160
+ stack {
161
+ // $input contains event data
162
+ // $channel contains matched channel
163
+ db.add "presence" {
164
+ data = {
165
+ user_id: $auth.id,
166
+ room_id: $input.room_id,
167
+ joined_at: now
168
+ }
169
+ }
170
+
171
+ // Notify room members
172
+ api.realtime_event {
173
+ channel = $channel
174
+ event = "user_joined"
175
+ data = { user_id: $auth.id }
176
+ }
177
+ }
178
+ }
179
+ ```
180
+
181
+ ### Channel Pattern Matching
182
+
183
+ ```xs
184
+ realtime_trigger "document_cursor" {
185
+ channel = "document:*" // Wildcard match
186
+ event = "cursor_move"
187
+ stack {
188
+ // Broadcast cursor position to other viewers
189
+ api.realtime_event {
190
+ channel = $channel
191
+ event = "cursor_update"
192
+ data = {
193
+ user_id: $auth.id,
194
+ position: $input.position
195
+ }
196
+ }
197
+ }
198
+ }
199
+ ```
200
+
201
+ ---
202
+
203
+ ## Common Patterns
204
+
205
+ ### Chat Application
206
+
207
+ ```xs
208
+ function "send_chat_message" {
209
+ input {
210
+ int room_id
211
+ text content filters=trim|max:1000
212
+ }
213
+ stack {
214
+ // Save message
215
+ db.add "message" {
216
+ data = {
217
+ room_id: $input.room_id,
218
+ sender_id: $auth.id,
219
+ content: $input.content,
220
+ created_at: now
221
+ }
222
+ } as $message
223
+
224
+ // Broadcast to room
225
+ api.realtime_event {
226
+ channel = "room:" ~ $input.room_id
227
+ event = "new_message"
228
+ data = {
229
+ id: $message.id,
230
+ sender_id: $auth.id,
231
+ content: $input.content,
232
+ created_at: $message.created_at
233
+ }
234
+ }
235
+ }
236
+ response = $message
237
+ }
238
+ ```
239
+
240
+ ### Live Dashboard Updates
241
+
242
+ ```xs
243
+ function "update_metrics" {
244
+ stack {
245
+ // Calculate metrics
246
+ db.query "order" {
247
+ where = $db.order.created_at >= now|transform_timestamp:"-1 hour"
248
+ } as $recent_orders
249
+
250
+ var $metrics {
251
+ value = {
252
+ orders_last_hour: $recent_orders|count,
253
+ revenue_last_hour: $recent_orders|map:$$.total|sum,
254
+ updated_at: now
255
+ }
256
+ }
257
+
258
+ // Push to dashboard subscribers
259
+ api.realtime_event {
260
+ channel = "dashboard:metrics"
261
+ event = "update"
262
+ data = $metrics
263
+ }
264
+ }
265
+ response = $metrics
266
+ }
267
+ ```
268
+
269
+ ### Collaborative Editing
270
+
271
+ ```xs
272
+ realtime_trigger "document_edit" {
273
+ channel = "document:*"
274
+ event = "operation"
275
+ stack {
276
+ // Apply operation to document
277
+ function.run "apply_document_op" {
278
+ input = {
279
+ document_id: $input.document_id,
280
+ operation: $input.operation,
281
+ user_id: $auth.id
282
+ }
283
+ } as $result
284
+
285
+ // Broadcast to other editors
286
+ api.realtime_event {
287
+ channel = $channel
288
+ event = "remote_operation"
289
+ data = {
290
+ operation: $input.operation,
291
+ user_id: $auth.id,
292
+ version: $result.version
293
+ }
294
+ }
295
+ }
296
+ }
297
+ ```
298
+
299
+ ### Notification System
300
+
301
+ ```xs
302
+ function "notify_user" {
303
+ input {
304
+ int user_id
305
+ text type
306
+ text title
307
+ text body
308
+ json? data
309
+ }
310
+ stack {
311
+ // Save notification
312
+ db.add "notification" {
313
+ data = {
314
+ user_id: $input.user_id,
315
+ type: $input.type,
316
+ title: $input.title,
317
+ body: $input.body,
318
+ data: $input.data,
319
+ read: false,
320
+ created_at: now
321
+ }
322
+ } as $notification
323
+
324
+ // Push to user
325
+ api.realtime_event {
326
+ channel = "user:" ~ $input.user_id
327
+ event = "notification"
328
+ data = $notification
329
+ }
330
+ }
331
+ response = $notification
332
+ }
333
+ ```
334
+
335
+ ---
336
+
337
+ ## Subscription Management
338
+
339
+ Clients subscribe to channels client-side. Server controls what events to send.
340
+
341
+ ### Authorization Pattern
342
+
343
+ ```xs
344
+ // Validate user can access channel before sending
345
+ function "send_to_room" {
346
+ input {
347
+ int room_id
348
+ text event
349
+ json data
350
+ }
351
+ stack {
352
+ // Check membership
353
+ db.query "room_member" {
354
+ where = $db.room_member.room_id == $input.room_id
355
+ && $db.room_member.user_id == $auth.id
356
+ return = { type: "exists" }
357
+ } as $is_member
358
+
359
+ precondition ($is_member) {
360
+ error_type = "accessdenied"
361
+ error = "Not a member of this room"
362
+ }
363
+
364
+ api.realtime_event {
365
+ channel = "room:" ~ $input.room_id
366
+ event = $input.event
367
+ data = $input.data
368
+ }
369
+ }
370
+ }
371
+ ```
372
+
373
+ ---
374
+
375
+ ## Best Practices
376
+
377
+ 1. **Use channel namespacing** - `type:id` format for clarity
378
+ 2. **Keep payloads small** - Send IDs, let client fetch details
379
+ 3. **Validate before broadcast** - Don't trust client event data
380
+ 4. **Use triggers for client events** - Handle incoming realtime events
381
+ 5. **Consider fan-out carefully** - Large broadcasts can be expensive
382
+ 6. **Implement presence** - Track who's connected to channels
@@ -0,0 +1,292 @@
1
+ ---
2
+ applyTo: "functions/**/*.xs, apis/**/*.xs"
3
+ ---
4
+
5
+ # Schema Operations
6
+
7
+ Runtime schema parsing and validation for dynamic data structures.
8
+
9
+ ## Quick Reference
10
+
11
+ | Function | Purpose |
12
+ |----------|---------|
13
+ | `schema.parse` | Parse and validate any schema |
14
+ | `schema.parse.object` | Parse object schema |
15
+ | `schema.parse.array` | Parse array schema |
16
+ | `schema.parse.attribute` | Parse single attribute |
17
+ | `schema.parse.constant` | Parse constant value |
18
+ | `schema.parse.enum` | Parse enum value |
19
+ | `schema.parse.immutable` | Parse immutable structure |
20
+
21
+ ---
22
+
23
+ ## schema.parse
24
+
25
+ Parse and validate data against a dynamic schema.
26
+
27
+ ```xs
28
+ schema.parse {
29
+ data = $input.payload
30
+ schema = {
31
+ type: "object",
32
+ properties: {
33
+ name: { type: "text", required: true },
34
+ email: { type: "email", filters: ["trim", "lower"] },
35
+ age: { type: "int", filters: ["min:0", "max:150"] }
36
+ }
37
+ }
38
+ } as $validated
39
+ ```
40
+
41
+ ### Schema Definition
42
+
43
+ | Property | Description |
44
+ |----------|-------------|
45
+ | `type` | Data type (text, int, decimal, bool, object, array, etc.) |
46
+ | `required` | Whether field is required (default: false) |
47
+ | `nullable` | Whether null is allowed (default: false) |
48
+ | `default` | Default value if not provided |
49
+ | `filters` | Array of validation filters |
50
+ | `properties` | Nested properties (for object type) |
51
+ | `items` | Item schema (for array type) |
52
+
53
+ ---
54
+
55
+ ## schema.parse.object
56
+
57
+ Parse and validate an object structure.
58
+
59
+ ```xs
60
+ schema.parse.object {
61
+ data = $input.user
62
+ schema = {
63
+ id: { type: "int", required: true },
64
+ profile: {
65
+ type: "object",
66
+ properties: {
67
+ name: { type: "text", required: true },
68
+ bio: { type: "text", nullable: true, filters: ["max:500"] }
69
+ }
70
+ },
71
+ roles: { type: "array", items: { type: "text" } }
72
+ }
73
+ } as $user
74
+ ```
75
+
76
+ ### With Defaults
77
+
78
+ ```xs
79
+ schema.parse.object {
80
+ data = $input.settings
81
+ schema = {
82
+ theme: { type: "text", default: "light" },
83
+ notifications: { type: "bool", default: true },
84
+ language: { type: "text", default: "en" }
85
+ }
86
+ } as $settings
87
+ ```
88
+
89
+ ---
90
+
91
+ ## schema.parse.array
92
+
93
+ Parse and validate an array structure.
94
+
95
+ ```xs
96
+ schema.parse.array {
97
+ data = $input.items
98
+ schema = {
99
+ min_items: 1,
100
+ max_items: 100,
101
+ items: {
102
+ type: "object",
103
+ properties: {
104
+ product_id: { type: "int", required: true },
105
+ quantity: { type: "int", required: true, filters: ["min:1"] }
106
+ }
107
+ }
108
+ }
109
+ } as $items
110
+ ```
111
+
112
+ ### Flat Array
113
+
114
+ ```xs
115
+ schema.parse.array {
116
+ data = $input.tags
117
+ schema = {
118
+ items: { type: "text", filters: ["trim", "lower"] },
119
+ unique: true
120
+ }
121
+ } as $tags
122
+ ```
123
+
124
+ ---
125
+
126
+ ## schema.parse.attribute
127
+
128
+ Parse a single attribute value.
129
+
130
+ ```xs
131
+ schema.parse.attribute {
132
+ data = $input.email
133
+ schema = {
134
+ type: "email",
135
+ required: true,
136
+ filters: ["trim", "lower"]
137
+ }
138
+ } as $email
139
+ ```
140
+
141
+ ### With Custom Validation
142
+
143
+ ```xs
144
+ schema.parse.attribute {
145
+ data = $input.phone
146
+ schema = {
147
+ type: "text",
148
+ pattern: "^\\+?[1-9]\\d{1,14}$",
149
+ error_message: "Invalid phone number format"
150
+ }
151
+ } as $phone
152
+ ```
153
+
154
+ ---
155
+
156
+ ## schema.parse.constant
157
+
158
+ Validate that a value matches an expected constant.
159
+
160
+ ```xs
161
+ schema.parse.constant {
162
+ data = $input.version
163
+ schema = {
164
+ value: "2.0",
165
+ error_message: "Only API version 2.0 is supported"
166
+ }
167
+ }
168
+ ```
169
+
170
+ ---
171
+
172
+ ## schema.parse.enum
173
+
174
+ Validate that a value is one of allowed options.
175
+
176
+ ```xs
177
+ schema.parse.enum {
178
+ data = $input.status
179
+ schema = {
180
+ values: ["pending", "active", "suspended", "closed"],
181
+ error_message: "Invalid status value"
182
+ }
183
+ } as $status
184
+ ```
185
+
186
+ ### With Default
187
+
188
+ ```xs
189
+ schema.parse.enum {
190
+ data = $input.priority
191
+ schema = {
192
+ values: ["low", "medium", "high"],
193
+ default: "medium"
194
+ }
195
+ } as $priority
196
+ ```
197
+
198
+ ---
199
+
200
+ ## schema.parse.immutable
201
+
202
+ Parse a structure that cannot be modified after parsing.
203
+
204
+ ```xs
205
+ schema.parse.immutable {
206
+ data = $input.config
207
+ schema = {
208
+ api_version: { type: "text", required: true },
209
+ features: { type: "array", items: { type: "text" } }
210
+ }
211
+ } as $config
212
+
213
+ // Attempting to modify $config will throw an error
214
+ ```
215
+
216
+ ---
217
+
218
+ ## Dynamic Schema Generation
219
+
220
+ Build schemas programmatically.
221
+
222
+ ```xs
223
+ function "validate_dynamic_form" {
224
+ input {
225
+ object form_config
226
+ object form_data
227
+ }
228
+ stack {
229
+ // Build schema from configuration
230
+ var $schema { value = { type: "object", properties: {} } }
231
+
232
+ foreach ($input.form_config.fields) {
233
+ each as $field {
234
+ var.update $schema.properties {
235
+ value = $schema.properties|set:$field.name:{
236
+ type: $field.type,
237
+ required: $field.required,
238
+ filters: $field.filters
239
+ }
240
+ }
241
+ }
242
+ }
243
+
244
+ // Validate form data against dynamic schema
245
+ schema.parse.object {
246
+ data = $input.form_data
247
+ schema = $schema.properties
248
+ } as $validated
249
+ }
250
+ response = $validated
251
+ }
252
+ ```
253
+
254
+ ---
255
+
256
+ ## Error Handling
257
+
258
+ Schema validation errors can be caught and handled.
259
+
260
+ ```xs
261
+ try_catch {
262
+ try {
263
+ schema.parse.object {
264
+ data = $input.payload
265
+ schema = $expected_schema
266
+ } as $validated
267
+ }
268
+ catch {
269
+ // $error contains validation details
270
+ // $error.field - which field failed
271
+ // $error.message - validation error message
272
+ // $error.value - the invalid value
273
+ throw {
274
+ name = "ValidationError"
275
+ value = {
276
+ field: $error.field,
277
+ message: $error.message
278
+ }
279
+ }
280
+ }
281
+ }
282
+ ```
283
+
284
+ ---
285
+
286
+ ## Best Practices
287
+
288
+ 1. **Define schemas upfront** - Use input blocks when structure is known
289
+ 2. **Use schema.parse for dynamic data** - External APIs, user-generated content
290
+ 3. **Validate at boundaries** - Parse external input, trust internal data
291
+ 4. **Provide clear error messages** - Use error_message for user-facing errors
292
+ 5. **Use immutable for config** - Prevent accidental modification