@xano/developer-mcp 1.0.1 → 1.0.2

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.
Files changed (42) hide show
  1. package/README.md +96 -31
  2. package/dist/index.js +248 -180
  3. package/package.json +4 -2
  4. package/xanoscript_docs/README.md +107 -1
  5. package/xanoscript_docs/agents.md +329 -0
  6. package/xanoscript_docs/apis.md +343 -0
  7. package/xanoscript_docs/database.md +417 -0
  8. package/xanoscript_docs/ephemeral.md +333 -0
  9. package/xanoscript_docs/frontend.md +291 -0
  10. package/xanoscript_docs/functions.md +232 -2035
  11. package/xanoscript_docs/integrations.md +439 -0
  12. package/xanoscript_docs/mcp-servers.md +190 -0
  13. package/xanoscript_docs/plan.md +192 -0
  14. package/xanoscript_docs/syntax.md +314 -0
  15. package/xanoscript_docs/tables.md +270 -0
  16. package/xanoscript_docs/tasks.md +254 -0
  17. package/xanoscript_docs/testing.md +335 -0
  18. package/xanoscript_docs/tools.md +305 -0
  19. package/xanoscript_docs/types.md +297 -0
  20. package/xanoscript_docs/version.json +2 -1
  21. package/xanoscript_docs/api_query_examples.md +0 -1255
  22. package/xanoscript_docs/api_query_guideline.md +0 -129
  23. package/xanoscript_docs/build_from_lovable.md +0 -715
  24. package/xanoscript_docs/db_query_guideline.md +0 -427
  25. package/xanoscript_docs/ephemeral_environment_guideline.md +0 -529
  26. package/xanoscript_docs/expression_guideline.md +0 -1086
  27. package/xanoscript_docs/frontend_guideline.md +0 -67
  28. package/xanoscript_docs/function_examples.md +0 -1406
  29. package/xanoscript_docs/function_guideline.md +0 -130
  30. package/xanoscript_docs/input_guideline.md +0 -227
  31. package/xanoscript_docs/mcp_server_examples.md +0 -36
  32. package/xanoscript_docs/mcp_server_guideline.md +0 -69
  33. package/xanoscript_docs/query_filter.md +0 -489
  34. package/xanoscript_docs/table_examples.md +0 -586
  35. package/xanoscript_docs/table_guideline.md +0 -137
  36. package/xanoscript_docs/task_examples.md +0 -511
  37. package/xanoscript_docs/task_guideline.md +0 -103
  38. package/xanoscript_docs/tips_and_tricks.md +0 -144
  39. package/xanoscript_docs/tool_examples.md +0 -69
  40. package/xanoscript_docs/tool_guideline.md +0 -139
  41. package/xanoscript_docs/unit_testing_guideline.md +0 -328
  42. package/xanoscript_docs/workspace.md +0 -17
@@ -0,0 +1,270 @@
1
+ ---
2
+ applyTo: "tables/*.xs"
3
+ ---
4
+
5
+ # Tables
6
+
7
+ Database table definitions in XanoScript.
8
+
9
+ ## Quick Reference
10
+
11
+ ```xs
12
+ table "<name>" {
13
+ auth = false # true if used for authentication
14
+ schema {
15
+ int id # Primary key (required)
16
+ text name filters=trim
17
+ timestamp created_at?=now
18
+ }
19
+ index = [
20
+ {type: "primary", field: [{name: "id"}]}
21
+ ]
22
+ }
23
+ ```
24
+
25
+ ### Field Types
26
+ `int`, `text`, `email`, `password`, `decimal`, `bool`, `timestamp`, `date`, `uuid`, `vector`, `json`, `image`, `video`, `audio`, `attachment`, `enum`
27
+
28
+ ### Index Types
29
+ `primary`, `btree`, `btree|unique`, `gin`
30
+
31
+ ---
32
+
33
+ ## Basic Structure
34
+
35
+ Every table requires an `id` field as the primary key:
36
+
37
+ ```xs
38
+ table "user" {
39
+ auth = true
40
+ schema {
41
+ int id
42
+ text name filters=trim
43
+ email email filters=trim|lower {
44
+ sensitive = true
45
+ }
46
+ password password
47
+ timestamp created_at?=now
48
+ }
49
+ index = [
50
+ {type: "primary", field: [{name: "id"}]}
51
+ {type: "btree|unique", field: [{name: "email"}]}
52
+ ]
53
+ }
54
+ ```
55
+
56
+ ---
57
+
58
+ ## Schema Fields
59
+
60
+ ### Basic Fields
61
+ ```xs
62
+ schema {
63
+ int id
64
+ text name
65
+ decimal price
66
+ bool is_active
67
+ timestamp created_at
68
+ date birth_date
69
+ }
70
+ ```
71
+
72
+ ### Optional & Defaults
73
+ ```xs
74
+ schema {
75
+ text nickname? # Optional, no default
76
+ timestamp created_at?=now # Optional, defaults to current time
77
+ bool is_active?=true # Optional, defaults to true
78
+ int status?=0 # Optional, defaults to 0
79
+ }
80
+ ```
81
+
82
+ ### With Filters
83
+ ```xs
84
+ schema {
85
+ text name filters=trim
86
+ email email filters=trim|lower
87
+ int quantity filters=min:0
88
+ text category filters=trim|lower
89
+ }
90
+ ```
91
+
92
+ ### With Metadata
93
+ ```xs
94
+ schema {
95
+ text ssn {
96
+ description = "Social Security Number"
97
+ sensitive = true
98
+ }
99
+ email email filters=lower {
100
+ description = "Primary contact email"
101
+ sensitive = true
102
+ }
103
+ }
104
+ ```
105
+
106
+ ### Foreign Keys
107
+ ```xs
108
+ schema {
109
+ int user_id {
110
+ table = "user"
111
+ description = "Reference to user table"
112
+ }
113
+ uuid order_id {
114
+ table = "order"
115
+ }
116
+ }
117
+ ```
118
+
119
+ ### Enum Fields
120
+ ```xs
121
+ schema {
122
+ enum status {
123
+ values = ["pending", "active", "completed", "cancelled"]
124
+ }
125
+ enum priority?="medium" {
126
+ values = ["low", "medium", "high"]
127
+ }
128
+ }
129
+ ```
130
+
131
+ ### JSON Fields
132
+ ```xs
133
+ schema {
134
+ json metadata
135
+ json settings?={}
136
+ }
137
+ ```
138
+
139
+ ### Vector Fields
140
+ ```xs
141
+ schema {
142
+ vector embedding # For AI/ML embeddings
143
+ }
144
+ ```
145
+
146
+ ---
147
+
148
+ ## Indexes
149
+
150
+ ### Primary Key
151
+ ```xs
152
+ index = [
153
+ {type: "primary", field: [{name: "id"}]}
154
+ ]
155
+ ```
156
+
157
+ ### B-tree Index
158
+ ```xs
159
+ index = [
160
+ {type: "btree", field: [{name: "email", op: "asc"}]}
161
+ {type: "btree", field: [{name: "created_at", op: "desc"}]}
162
+ ]
163
+ ```
164
+
165
+ ### Unique Index
166
+ ```xs
167
+ index = [
168
+ {type: "btree|unique", field: [{name: "email"}]}
169
+ {type: "btree|unique", field: [{name: "username"}]}
170
+ ]
171
+ ```
172
+
173
+ ### Composite Index
174
+ ```xs
175
+ index = [
176
+ {type: "btree", field: [{name: "user_id"}, {name: "created_at", op: "desc"}]}
177
+ ]
178
+ ```
179
+
180
+ ### GIN Index (for JSON/arrays)
181
+ ```xs
182
+ index = [
183
+ {type: "gin", field: [{name: "tags", op: "jsonb_path_op"}]}
184
+ {type: "gin", field: [{name: "metadata", op: "jsonb_path_op"}]}
185
+ ]
186
+ ```
187
+
188
+ ---
189
+
190
+ ## Complete Examples
191
+
192
+ ### User Table (with auth)
193
+ ```xs
194
+ table "user" {
195
+ auth = true
196
+ schema {
197
+ int id
198
+ text name filters=trim
199
+ email email filters=trim|lower { sensitive = true }
200
+ password password { sensitive = true }
201
+ enum role?="user" { values = ["user", "admin", "moderator"] }
202
+ bool is_active?=true
203
+ timestamp created_at?=now
204
+ timestamp updated_at?
205
+ }
206
+ index = [
207
+ {type: "primary", field: [{name: "id"}]}
208
+ {type: "btree|unique", field: [{name: "email"}]}
209
+ {type: "btree", field: [{name: "role"}]}
210
+ ]
211
+ }
212
+ ```
213
+
214
+ ### Product Table
215
+ ```xs
216
+ table "product" {
217
+ auth = false
218
+ schema {
219
+ int id
220
+ text name filters=trim
221
+ text description?
222
+ decimal price filters=min:0
223
+ int stock_quantity?=0 filters=min:0
224
+ int category_id { table = "category" }
225
+ json metadata?
226
+ bool is_published?=false
227
+ timestamp created_at?=now
228
+ }
229
+ index = [
230
+ {type: "primary", field: [{name: "id"}]}
231
+ {type: "btree", field: [{name: "category_id"}]}
232
+ {type: "btree", field: [{name: "is_published"}]}
233
+ ]
234
+ }
235
+ ```
236
+
237
+ ### Order with Foreign Keys
238
+ ```xs
239
+ table "order" {
240
+ auth = false
241
+ schema {
242
+ int id
243
+ int user_id { table = "user" }
244
+ decimal total filters=min:0
245
+ enum status?="pending" { values = ["pending", "processing", "shipped", "delivered", "cancelled"] }
246
+ json shipping_address
247
+ timestamp created_at?=now
248
+ timestamp updated_at?
249
+ }
250
+ index = [
251
+ {type: "primary", field: [{name: "id"}]}
252
+ {type: "btree", field: [{name: "user_id"}]}
253
+ {type: "btree", field: [{name: "status"}]}
254
+ {type: "btree", field: [{name: "created_at", op: "desc"}]}
255
+ ]
256
+ }
257
+ ```
258
+
259
+ ---
260
+
261
+ ## Best Practices
262
+
263
+ 1. **Always define `id`** - Every table needs a primary key named `id`
264
+ 2. **Use `auth = true`** only for authentication tables (typically just `user`)
265
+ 3. **Add indexes** for fields used in WHERE clauses and JOINs
266
+ 4. **Use appropriate types** - `email` for emails, `password` for credentials
267
+ 5. **Mark sensitive fields** - Set `sensitive = true` for PII
268
+ 6. **Use filters** - Apply `trim`, `lower` for consistency
269
+ 7. **Default timestamps** - Use `?=now` for created_at fields
270
+ 8. **Document with descriptions** - Add descriptions for non-obvious fields
@@ -0,0 +1,254 @@
1
+ ---
2
+ applyTo: "tasks/*.xs"
3
+ ---
4
+
5
+ # Tasks
6
+
7
+ Scheduled jobs in XanoScript.
8
+
9
+ ## Quick Reference
10
+
11
+ ```xs
12
+ task "<name>" {
13
+ description = "What this task does"
14
+ stack { ... }
15
+ schedule = [{starts_on: YYYY-MM-DD HH:MM:SS+0000, freq: <seconds>}]
16
+ }
17
+ ```
18
+
19
+ ### Common Frequencies
20
+ | Interval | Seconds |
21
+ |----------|---------|
22
+ | 1 minute | 60 |
23
+ | 5 minutes | 300 |
24
+ | 1 hour | 3600 |
25
+ | Daily | 86400 |
26
+ | Weekly | 604800 |
27
+
28
+ ---
29
+
30
+ ## Basic Structure
31
+
32
+ ```xs
33
+ task "daily_cleanup" {
34
+ description = "Clean up expired sessions daily at midnight UTC"
35
+ stack {
36
+ db.query "session" {
37
+ where = $db.session.expires_at < now
38
+ } as $expired
39
+
40
+ foreach ($expired) {
41
+ each as $session {
42
+ db.del "session" {
43
+ field_name = "id"
44
+ field_value = $session.id
45
+ }
46
+ }
47
+ }
48
+
49
+ debug.log { value = "Cleaned " ~ ($expired|count) ~ " sessions" }
50
+ }
51
+ schedule = [{starts_on: 2025-01-01 00:00:00+0000, freq: 86400}]
52
+ }
53
+ ```
54
+
55
+ ---
56
+
57
+ ## Schedule Configuration
58
+
59
+ ### Single Event
60
+ ```xs
61
+ schedule = [{starts_on: 2025-06-15 09:00:00+0000, freq: 86400}]
62
+ ```
63
+
64
+ ### With End Date
65
+ ```xs
66
+ schedule = [{
67
+ starts_on: 2025-01-01 08:00:00+0000,
68
+ freq: 3600,
69
+ ends_on: 2025-12-31 23:59:59+0000
70
+ }]
71
+ ```
72
+
73
+ ### Multiple Schedules
74
+ ```xs
75
+ schedule = [
76
+ {starts_on: 2025-01-01 09:00:00+0000, freq: 86400},
77
+ {starts_on: 2025-01-01 21:00:00+0000, freq: 86400}
78
+ ]
79
+ ```
80
+
81
+ ---
82
+
83
+ ## Common Patterns
84
+
85
+ ### Data Aggregation
86
+ ```xs
87
+ task "hourly_stats" {
88
+ description = "Aggregate hourly statistics"
89
+ stack {
90
+ var $hour_ago { value = now|transform_timestamp:"-1 hour" }
91
+
92
+ db.query "order" {
93
+ where = $db.order.created_at >= $hour_ago
94
+ } as $orders
95
+
96
+ db.add "hourly_stats" {
97
+ data = {
98
+ hour: $hour_ago,
99
+ order_count: $orders|count,
100
+ total_revenue: ($orders|map:$$.total)|sum
101
+ }
102
+ }
103
+ }
104
+ schedule = [{starts_on: 2025-01-01 00:00:00+0000, freq: 3600}]
105
+ }
106
+ ```
107
+
108
+ ### Cleanup Job
109
+ ```xs
110
+ task "cleanup_temp_files" {
111
+ description = "Delete temporary files older than 24 hours"
112
+ stack {
113
+ var $cutoff { value = now|transform_timestamp:"-24 hours" }
114
+
115
+ db.query "temp_file" {
116
+ where = $db.temp_file.created_at < $cutoff
117
+ } as $files
118
+
119
+ foreach ($files) {
120
+ each as $file {
121
+ storage.delete_file { pathname = $file.path }
122
+ db.del "temp_file" {
123
+ field_name = "id"
124
+ field_value = $file.id
125
+ }
126
+ }
127
+ }
128
+ }
129
+ schedule = [{starts_on: 2025-01-01 03:00:00+0000, freq: 86400}]
130
+ }
131
+ ```
132
+
133
+ ### Notification Job
134
+ ```xs
135
+ task "daily_digest" {
136
+ description = "Send daily digest emails"
137
+ stack {
138
+ db.query "user" {
139
+ where = $db.user.digest_enabled == true
140
+ } as $users
141
+
142
+ foreach ($users) {
143
+ each as $user {
144
+ db.query "notification" {
145
+ where = $db.notification.user_id == $user.id
146
+ && $db.notification.sent == false
147
+ } as $notifications
148
+
149
+ conditional {
150
+ if (($notifications|count) > 0) {
151
+ util.send_email {
152
+ service_provider = "resend"
153
+ api_key = $env.RESEND_API_KEY
154
+ to = $user.email
155
+ from = "noreply@example.com"
156
+ subject = "Your Daily Digest"
157
+ message = "You have " ~ ($notifications|count) ~ " new notifications"
158
+ }
159
+ }
160
+ }
161
+ }
162
+ }
163
+ }
164
+ schedule = [{starts_on: 2025-01-01 08:00:00+0000, freq: 86400}]
165
+ }
166
+ ```
167
+
168
+ ### External API Sync
169
+ ```xs
170
+ task "sync_exchange_rates" {
171
+ description = "Sync currency exchange rates every hour"
172
+ stack {
173
+ api.request {
174
+ url = "https://api.exchangerate.com/latest"
175
+ method = "GET"
176
+ headers = []|push:("Authorization: Bearer " ~ $env.EXCHANGE_API_KEY)
177
+ } as $response
178
+
179
+ foreach ($response.rates|entries) {
180
+ each as $rate {
181
+ db.add_or_edit "exchange_rate" {
182
+ field_name = "currency"
183
+ field_value = $rate.key
184
+ data = {
185
+ currency: $rate.key,
186
+ rate: $rate.value,
187
+ updated_at: now
188
+ }
189
+ }
190
+ }
191
+ }
192
+ }
193
+ schedule = [{starts_on: 2025-01-01 00:00:00+0000, freq: 3600}]
194
+ }
195
+ ```
196
+
197
+ ---
198
+
199
+ ## Stack Operations
200
+
201
+ Tasks use the same stack operations as functions:
202
+
203
+ - `db.query`, `db.add`, `db.edit`, `db.del` - Database operations
204
+ - `api.request` - External API calls
205
+ - `function.run` - Call functions
206
+ - `foreach`, `for`, `while` - Loops
207
+ - `conditional` - Branching
208
+ - `debug.log` - Logging
209
+ - `util.send_email` - Send emails
210
+ - `try_catch` - Error handling
211
+
212
+ ---
213
+
214
+ ## Error Handling
215
+
216
+ ```xs
217
+ task "risky_sync" {
218
+ stack {
219
+ try_catch {
220
+ try {
221
+ api.request {
222
+ url = "https://external-api.com/data"
223
+ method = "GET"
224
+ } as $data
225
+ # Process data...
226
+ }
227
+ catch {
228
+ util.send_email {
229
+ service_provider = "resend"
230
+ api_key = $env.RESEND_API_KEY
231
+ to = "alerts@example.com"
232
+ from = "system@example.com"
233
+ subject = "Sync Task Failed"
234
+ message = "The risky_sync task failed"
235
+ }
236
+ }
237
+ }
238
+ }
239
+ schedule = [{starts_on: 2025-01-01 00:00:00+0000, freq: 3600}]
240
+ }
241
+ ```
242
+
243
+ ---
244
+
245
+ ## Best Practices
246
+
247
+ 1. **Use descriptive names** - Indicate what and when: `daily_cleanup`, `hourly_sync`
248
+ 2. **Add descriptions** - Explain the purpose and schedule
249
+ 3. **Handle errors** - Use try_catch for external dependencies
250
+ 4. **Log important events** - Use debug.log for tracking
251
+ 5. **Use appropriate frequency** - Don't run more often than needed
252
+ 6. **Consider timezone** - Schedule uses UTC (+0000)
253
+ 7. **Batch operations** - Process in chunks for large datasets
254
+ 8. **Set end dates** - Use ends_on for temporary schedules