@xano/developer-mcp 1.0.5 → 1.0.6
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/dist/index.js +5 -0
- package/dist/templates/xanoscript-index.js +1 -0
- package/package.json +1 -1
- package/xanoscript_docs/README.md +20 -14
- package/xanoscript_docs/agents.md +1 -3
- package/xanoscript_docs/apis.md +15 -75
- package/xanoscript_docs/database.md +1 -4
- package/xanoscript_docs/ephemeral.md +3 -6
- package/xanoscript_docs/frontend.md +2 -5
- package/xanoscript_docs/functions.md +4 -55
- package/xanoscript_docs/mcp-servers.md +3 -6
- package/xanoscript_docs/syntax.md +70 -0
- package/xanoscript_docs/tables.md +1 -4
- package/xanoscript_docs/tasks.md +5 -8
- package/xanoscript_docs/testing.md +5 -8
- package/xanoscript_docs/tools.md +3 -11
- package/xanoscript_docs/triggers.md +532 -0
- package/xanoscript_docs/types.md +6 -16
- package/xanoscript_docs/plan.md +0 -192
package/dist/index.js
CHANGED
|
@@ -47,6 +47,11 @@ const XANOSCRIPT_DOCS_V2 = {
|
|
|
47
47
|
applyTo: ["tasks/*.xs"],
|
|
48
48
|
description: "Scheduled and cron jobs",
|
|
49
49
|
},
|
|
50
|
+
triggers: {
|
|
51
|
+
file: "triggers.md",
|
|
52
|
+
applyTo: ["triggers/**/*.xs"],
|
|
53
|
+
description: "Event-driven handlers (table, realtime, workspace, agent, MCP)",
|
|
54
|
+
},
|
|
50
55
|
database: {
|
|
51
56
|
file: "database.md",
|
|
52
57
|
applyTo: ["functions/**/*.xs", "apis/**/*.xs", "tasks/*.xs", "tools/**/*.xs"],
|
|
@@ -22,6 +22,7 @@ ${formatRow("function", "Custom reusable functions in `functions/`")}
|
|
|
22
22
|
${formatRow("api_query", "HTTP API endpoints in `apis/`")}
|
|
23
23
|
${formatRow("table", "Database table schemas in `tables/`")}
|
|
24
24
|
${formatRow("task", "Scheduled background tasks in `tasks/`")}
|
|
25
|
+
${formatRow("triggers", "Event-driven handlers in `triggers/`")}
|
|
25
26
|
${formatRow("tool", "AI-callable tools in `tools/`")}
|
|
26
27
|
${formatRow("agent", "AI agents in `agents/`")}
|
|
27
28
|
${formatRow("mcp_server", "MCP servers in `mcp_servers/`")}
|
package/package.json
CHANGED
|
@@ -10,6 +10,7 @@ XanoScript is the declarative scripting language for [Xano](https://xano.com), a
|
|
|
10
10
|
| `function` | `functions/**/*.xs` | Reusable logic blocks |
|
|
11
11
|
| `query` | `apis/<group>/*.xs` | HTTP API endpoints |
|
|
12
12
|
| `task` | `tasks/*.xs` | Scheduled/cron jobs |
|
|
13
|
+
| `*_trigger` | `triggers/**/*.xs` | Event-driven handlers |
|
|
13
14
|
| `agent` | `agents/**/*.xs` | AI-powered agents |
|
|
14
15
|
| `tool` | `tools/**/*.xs` | Tools for AI agents |
|
|
15
16
|
| `mcp_server` | `mcp_servers/**/*.xs` | MCP server definitions |
|
|
@@ -24,6 +25,7 @@ project/
|
|
|
24
25
|
├── apis/
|
|
25
26
|
│ └── <api-group>/ # API endpoints grouped by domain
|
|
26
27
|
├── tasks/ # Scheduled jobs
|
|
28
|
+
├── triggers/ # Event-driven handlers
|
|
27
29
|
├── agents/ # AI agents
|
|
28
30
|
├── tools/ # AI tools
|
|
29
31
|
├── mcp_servers/ # MCP server definitions
|
|
@@ -91,17 +93,21 @@ This helps AI tools apply the correct documentation based on the file being edit
|
|
|
91
93
|
|
|
92
94
|
## Documentation Index
|
|
93
95
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
96
|
+
Use `xanoscript_docs({ keyword: "<keyword>" })` to retrieve documentation.
|
|
97
|
+
|
|
98
|
+
| Topic | Keyword | Description |
|
|
99
|
+
|-------|---------|-------------|
|
|
100
|
+
| Syntax Reference | `syntax` | Expressions, operators, filters |
|
|
101
|
+
| Types & Inputs | `input` | Data types, validation, input blocks |
|
|
102
|
+
| Tables | `table` | Database schema definitions |
|
|
103
|
+
| Functions | `function` | Reusable function stacks |
|
|
104
|
+
| APIs | `api_query` | HTTP endpoint definitions |
|
|
105
|
+
| Tasks | `task` | Scheduled jobs |
|
|
106
|
+
| Triggers | `trigger` | Event-driven handlers (table, realtime, workspace, agent, MCP) |
|
|
107
|
+
| Database Operations | `db_query` | Query, add, edit, delete |
|
|
108
|
+
| Agents | `agent` | AI agent configuration |
|
|
109
|
+
| Tools | `tool` | AI tools for agents |
|
|
110
|
+
| MCP Servers | `mcp_server` | Model Context Protocol servers |
|
|
111
|
+
| Testing | `testing` | Unit tests and mocking |
|
|
112
|
+
| Frontend | `frontend` | Static frontend development |
|
|
113
|
+
| Ephemeral | `ephemeral` | Temporary environments
|
|
@@ -324,6 +324,4 @@ agent "Research Assistant" {
|
|
|
324
324
|
3. **Limit max_steps** - Prevent infinite loops (3-10 typical)
|
|
325
325
|
4. **Don't repeat tool descriptions** - They're auto-injected
|
|
326
326
|
5. **Use environment variables** - Never hardcode API keys
|
|
327
|
-
6. **
|
|
328
|
-
7. **Test with xano-free first** - Free for development
|
|
329
|
-
8. **Use structured outputs** - When you need consistent JSON
|
|
327
|
+
6. **Test with xano-free first** - Free for development
|
package/xanoscript_docs/apis.md
CHANGED
|
@@ -38,61 +38,28 @@ The query name can include slashes for nested paths:
|
|
|
38
38
|
|
|
39
39
|
### API Groups (Required)
|
|
40
40
|
|
|
41
|
-
Every
|
|
42
|
-
|
|
43
|
-
**Two requirements for API groups:**
|
|
44
|
-
1. Each `query` definition **must** include an `api_group` property specifying which group it belongs to
|
|
45
|
-
2. API groups are organized as folders within `apis/`, each with an `api_group.xs` file
|
|
46
|
-
|
|
47
|
-
- API groups appear as top-level folders under `apis/`
|
|
48
|
-
- Each group **must** have an `api_group.xs` file that defines the group
|
|
49
|
-
- The group contains `.xs` files defining individual endpoints
|
|
50
|
-
- The group name becomes part of the endpoint URL path
|
|
51
|
-
- You cannot create endpoints directly in the `apis/` root folder
|
|
52
|
-
|
|
53
|
-
#### Defining an API Group
|
|
54
|
-
|
|
55
|
-
Create an `api_group.xs` file in the group folder:
|
|
41
|
+
Every endpoint must belong to an API group. Each group is a folder with an `api_group.xs` file:
|
|
56
42
|
|
|
57
43
|
```xs
|
|
58
44
|
api_group "users" {
|
|
59
|
-
canonical = "users" # Required:
|
|
60
|
-
description = "User management
|
|
45
|
+
canonical = "users" # Required: URL path segment
|
|
46
|
+
description = "User management" # Optional
|
|
61
47
|
}
|
|
62
48
|
```
|
|
63
49
|
|
|
64
|
-
#### API Group Properties
|
|
65
|
-
|
|
66
|
-
| Property | Required | Description |
|
|
67
|
-
|----------|----------|-------------|
|
|
68
|
-
| `canonical` | **Yes** | The URL path segment for this group. You cannot access a Xano API without it. |
|
|
69
|
-
| `description` | No | What this API group contains |
|
|
70
|
-
|
|
71
|
-
```xs
|
|
72
|
-
api_group "events" {
|
|
73
|
-
canonical = "events-api" # Required: URL will use /events-api
|
|
74
|
-
description = "Event management"
|
|
75
|
-
}
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
> **Important:** The `canonical` property is required. It defines the base path for all endpoints in this group.
|
|
79
|
-
|
|
80
50
|
### File Structure
|
|
81
51
|
```
|
|
82
52
|
apis/
|
|
83
|
-
├── users/
|
|
84
|
-
│ ├── api_group.xs #
|
|
53
|
+
├── users/
|
|
54
|
+
│ ├── api_group.xs # Defines group (canonical = "users")
|
|
85
55
|
│ ├── list.xs # GET /users/list
|
|
86
|
-
│ ├── create.xs # POST /users/create
|
|
87
56
|
│ └── by-id.xs # GET/PATCH/DELETE /users/{id}
|
|
88
|
-
└── products/
|
|
89
|
-
├── api_group.xs #
|
|
57
|
+
└── products/
|
|
58
|
+
├── api_group.xs # Defines group (canonical = "products")
|
|
90
59
|
└── search.xs # GET /products/search
|
|
91
60
|
```
|
|
92
61
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
> **Note:** Files placed directly in `apis/` without a group folder are invalid. Each API group folder must contain an `api_group.xs` file.
|
|
62
|
+
Full URL: `/<canonical>/<query name>` (e.g., `/users/profile`)
|
|
96
63
|
|
|
97
64
|
---
|
|
98
65
|
|
|
@@ -354,33 +321,11 @@ stack {
|
|
|
354
321
|
|
|
355
322
|
## Error Handling
|
|
356
323
|
|
|
357
|
-
|
|
358
|
-
```xs
|
|
359
|
-
stack {
|
|
360
|
-
precondition ($input.amount > 0) {
|
|
361
|
-
error_type = "inputerror"
|
|
362
|
-
error = "Amount must be positive"
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
precondition ($user != null) {
|
|
366
|
-
error_type = "notfound"
|
|
367
|
-
error = "User not found"
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
precondition ($user.id == $auth.id) {
|
|
371
|
-
error_type = "accessdenied"
|
|
372
|
-
error = "Not authorized"
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
```
|
|
324
|
+
For complete error handling reference, use `xanoscript_docs({ keyword: "syntax" })`.
|
|
376
325
|
|
|
377
|
-
### Error Types
|
|
378
326
|
| Type | HTTP Status |
|
|
379
327
|
|------|-------------|
|
|
380
|
-
| `inputerror` | 400
|
|
381
|
-
| `accessdenied` | 403 Forbidden |
|
|
382
|
-
| `notfound` | 404 Not Found |
|
|
383
|
-
| `standard` | 500 Internal Server Error |
|
|
328
|
+
| `inputerror` | 400 | `accessdenied` | 403 | `notfound` | 404 | `standard` | 500 |
|
|
384
329
|
|
|
385
330
|
---
|
|
386
331
|
|
|
@@ -404,13 +349,8 @@ When using `return = { type: "list", paging: {...} }`:
|
|
|
404
349
|
|
|
405
350
|
## Best Practices
|
|
406
351
|
|
|
407
|
-
1. **
|
|
408
|
-
2. **
|
|
409
|
-
3. **
|
|
410
|
-
4. **
|
|
411
|
-
5. **
|
|
412
|
-
6. **Validate inputs** - Use filters and preconditions
|
|
413
|
-
7. **Return appropriate errors** - Use correct error types
|
|
414
|
-
8. **Paginate lists** - Never return unbounded lists
|
|
415
|
-
9. **Document with description** - Explain what endpoint does
|
|
416
|
-
10. **Group related endpoints** - Organize by resource in api groups
|
|
352
|
+
1. **RESTful design** - Use appropriate HTTP methods for operations
|
|
353
|
+
2. **Consistent naming** - Use lowercase, hyphens for multi-word paths
|
|
354
|
+
3. **Authenticate writes** - Always require auth for POST/PATCH/DELETE
|
|
355
|
+
4. **Paginate lists** - Never return unbounded result sets
|
|
356
|
+
5. **Group by resource** - Organize endpoints in logical api groups
|
|
@@ -411,7 +411,4 @@ db.external.oracle.direct_query { ... }
|
|
|
411
411
|
2. **Use db.get for single lookups** - Simpler than db.query with single return
|
|
412
412
|
3. **Use db.patch for dynamic updates** - Accepts variable data
|
|
413
413
|
4. **Use transactions for atomicity** - Ensure all-or-nothing operations
|
|
414
|
-
5. **
|
|
415
|
-
6. **Use null-safe operators** - `==?` for optional filters
|
|
416
|
-
7. **Paginate results** - Never return unbounded lists
|
|
417
|
-
8. **Validate before delete** - Check ownership/permissions
|
|
414
|
+
5. **Use null-safe operators** - `==?` for optional filters
|
|
@@ -325,9 +325,6 @@ publish_ephemeral_service name="migration" directory="ephemeral/my-job" mode="jo
|
|
|
325
325
|
|
|
326
326
|
1. **Keep isolated** - Self-contained with own tables/functions
|
|
327
327
|
2. **Seed test data** - Use `items` in table definitions
|
|
328
|
-
3. **
|
|
329
|
-
4. **
|
|
330
|
-
5. **
|
|
331
|
-
6. **Use preconditions** - Verify expected outcomes in jobs
|
|
332
|
-
7. **Name clearly** - Indicate purpose: `auth-test`, `data-migration`
|
|
333
|
-
8. **Set end dates** - Use `ends_on` for temporary schedules
|
|
328
|
+
3. **Handle cleanup** - Use `$post` for notifications/cleanup
|
|
329
|
+
4. **Validate in $pre** - Check preconditions before main logic
|
|
330
|
+
5. **Name clearly** - Indicate purpose: `auth-test`, `data-migration`
|
|
@@ -284,8 +284,5 @@ The tool will:
|
|
|
284
284
|
|
|
285
285
|
1. **Get API specs first** - Use `get_xano_api_specifications` before coding
|
|
286
286
|
2. **Centralize API calls** - Single `api.js` file
|
|
287
|
-
3. **
|
|
288
|
-
4. **
|
|
289
|
-
5. **Validate before submit** - Client-side validation before API calls
|
|
290
|
-
6. **Use loading states** - Show progress during API calls
|
|
291
|
-
7. **Test incrementally** - Migrate one feature at a time
|
|
287
|
+
3. **Store tokens securely** - localStorage for web, secure storage for mobile
|
|
288
|
+
4. **Test incrementally** - Migrate one feature at a time
|
|
@@ -63,20 +63,13 @@ Reference with path: `function.run "math/add" { ... }`
|
|
|
63
63
|
|
|
64
64
|
## Input Block
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
For complete type and filter reference, use `xanoscript_docs({ keyword: "input" })`.
|
|
67
67
|
|
|
68
68
|
```xs
|
|
69
69
|
input {
|
|
70
70
|
text name filters=trim
|
|
71
71
|
int age? filters=min:0
|
|
72
72
|
email contact filters=lower { sensitive = true }
|
|
73
|
-
object address? {
|
|
74
|
-
schema {
|
|
75
|
-
text street
|
|
76
|
-
text city
|
|
77
|
-
text zip
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
73
|
}
|
|
81
74
|
```
|
|
82
75
|
|
|
@@ -158,49 +151,8 @@ stack {
|
|
|
158
151
|
```
|
|
159
152
|
|
|
160
153
|
### Error Handling
|
|
161
|
-
```xs
|
|
162
|
-
stack {
|
|
163
|
-
try_catch {
|
|
164
|
-
try {
|
|
165
|
-
function.run "risky_operation" { input = {} } as $result
|
|
166
|
-
}
|
|
167
|
-
catch {
|
|
168
|
-
debug.log { value = "Operation failed" }
|
|
169
|
-
var $result { value = null }
|
|
170
|
-
}
|
|
171
|
-
finally {
|
|
172
|
-
debug.log { value = "Cleanup complete" }
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
```
|
|
177
154
|
|
|
178
|
-
|
|
179
|
-
```xs
|
|
180
|
-
stack {
|
|
181
|
-
precondition ($input.amount > 0) {
|
|
182
|
-
error_type = "inputerror"
|
|
183
|
-
error = "Amount must be positive"
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
throw {
|
|
187
|
-
name = "ValidationError"
|
|
188
|
-
value = "Custom error message"
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
### Early Return
|
|
194
|
-
```xs
|
|
195
|
-
stack {
|
|
196
|
-
conditional {
|
|
197
|
-
if ($input.skip) {
|
|
198
|
-
return { value = null }
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
# Continue processing...
|
|
202
|
-
}
|
|
203
|
-
```
|
|
155
|
+
For complete error handling reference (preconditions, try-catch, throw, early return), use `xanoscript_docs({ keyword: "syntax" })`.
|
|
204
156
|
|
|
205
157
|
---
|
|
206
158
|
|
|
@@ -345,8 +297,5 @@ function "validate_email_unique" {
|
|
|
345
297
|
1. **Single responsibility** - Each function does one thing well
|
|
346
298
|
2. **Descriptive names** - Use verb_noun format: `calculate_total`, `validate_user`
|
|
347
299
|
3. **Organize in folders** - Group related functions: `utils/`, `auth/`, `orders/`
|
|
348
|
-
4. **
|
|
349
|
-
5. **
|
|
350
|
-
6. **Document purpose** - Add description field
|
|
351
|
-
7. **Return early** - Use return for guard clauses
|
|
352
|
-
8. **Keep stacks shallow** - Avoid deeply nested conditionals
|
|
300
|
+
4. **Return early** - Use return for guard clauses
|
|
301
|
+
5. **Keep stacks shallow** - Avoid deeply nested conditionals
|
|
@@ -182,9 +182,6 @@ The MCP protocol handles:
|
|
|
182
182
|
## Best Practices
|
|
183
183
|
|
|
184
184
|
1. **Clear naming** - Server name should indicate its purpose
|
|
185
|
-
2. **
|
|
186
|
-
3. **
|
|
187
|
-
4. **
|
|
188
|
-
5. **Use tags** - Organize servers by category
|
|
189
|
-
6. **Keep focused** - One domain per server (support, analytics, etc.)
|
|
190
|
-
7. **Document internally** - Use description for team documentation
|
|
185
|
+
2. **Comprehensive instructions** - Guide AI on server's overall purpose
|
|
186
|
+
3. **Logical tool grouping** - Group related tools in one server
|
|
187
|
+
4. **Keep focused** - One domain per server (support, analytics, etc.)
|
|
@@ -312,3 +312,73 @@ Used in `db.query` where clauses:
|
|
|
312
312
|
$db.created_at|timestamp_add_days:7
|
|
313
313
|
$db.created_at|timestamp_subtract_hours:24
|
|
314
314
|
```
|
|
315
|
+
|
|
316
|
+
---
|
|
317
|
+
|
|
318
|
+
## Error Handling
|
|
319
|
+
|
|
320
|
+
### Preconditions
|
|
321
|
+
|
|
322
|
+
Validate conditions and throw typed errors:
|
|
323
|
+
|
|
324
|
+
```xs
|
|
325
|
+
precondition ($input.amount > 0) {
|
|
326
|
+
error_type = "inputerror"
|
|
327
|
+
error = "Amount must be positive"
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
precondition ($user != null) {
|
|
331
|
+
error_type = "notfound"
|
|
332
|
+
error = "User not found"
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
precondition ($user.id == $auth.id) {
|
|
336
|
+
error_type = "accessdenied"
|
|
337
|
+
error = "Not authorized"
|
|
338
|
+
}
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### Error Types
|
|
342
|
+
|
|
343
|
+
| Type | HTTP Status | Use Case |
|
|
344
|
+
|------|-------------|----------|
|
|
345
|
+
| `inputerror` | 400 Bad Request | Invalid input data |
|
|
346
|
+
| `accessdenied` | 403 Forbidden | Authorization failure |
|
|
347
|
+
| `notfound` | 404 Not Found | Resource doesn't exist |
|
|
348
|
+
| `standard` | 500 Internal Server Error | General errors |
|
|
349
|
+
|
|
350
|
+
### Throwing Errors
|
|
351
|
+
|
|
352
|
+
```xs
|
|
353
|
+
throw {
|
|
354
|
+
name = "ValidationError"
|
|
355
|
+
value = "Custom error message"
|
|
356
|
+
}
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
### Try-Catch
|
|
360
|
+
|
|
361
|
+
```xs
|
|
362
|
+
try_catch {
|
|
363
|
+
try {
|
|
364
|
+
function.run "risky_operation" { input = {} } as $result
|
|
365
|
+
}
|
|
366
|
+
catch {
|
|
367
|
+
debug.log { value = "Operation failed" }
|
|
368
|
+
var $result { value = null }
|
|
369
|
+
}
|
|
370
|
+
finally {
|
|
371
|
+
debug.log { value = "Cleanup complete" }
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
### Early Return
|
|
377
|
+
|
|
378
|
+
```xs
|
|
379
|
+
conditional {
|
|
380
|
+
if ($input.skip) {
|
|
381
|
+
return { value = null }
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
```
|
|
@@ -264,7 +264,4 @@ table "order" {
|
|
|
264
264
|
2. **Use `auth = true`** only for authentication tables (typically just `user`)
|
|
265
265
|
3. **Add indexes** for fields used in WHERE clauses and JOINs
|
|
266
266
|
4. **Use appropriate types** - `email` for emails, `password` for credentials
|
|
267
|
-
5. **
|
|
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
|
|
267
|
+
5. **Default timestamps** - Use `?=now` for created_at fields
|
package/xanoscript_docs/tasks.md
CHANGED
|
@@ -244,11 +244,8 @@ task "risky_sync" {
|
|
|
244
244
|
|
|
245
245
|
## Best Practices
|
|
246
246
|
|
|
247
|
-
1. **
|
|
248
|
-
2. **
|
|
249
|
-
3. **
|
|
250
|
-
4. **
|
|
251
|
-
5. **
|
|
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
|
|
247
|
+
1. **Descriptive names** - Indicate what and when: `daily_cleanup`, `hourly_sync`
|
|
248
|
+
2. **Handle errors** - Use try_catch for external dependencies
|
|
249
|
+
3. **Consider timezone** - Schedule uses UTC (+0000)
|
|
250
|
+
4. **Batch operations** - Process in chunks for large datasets
|
|
251
|
+
5. **Set end dates** - Use ends_on for temporary schedules
|
|
@@ -325,11 +325,8 @@ function "calculate_discount" {
|
|
|
325
325
|
|
|
326
326
|
## Best Practices
|
|
327
327
|
|
|
328
|
-
1. **Test happy paths** -
|
|
329
|
-
2. **
|
|
330
|
-
3. **
|
|
331
|
-
4. **
|
|
332
|
-
5. **
|
|
333
|
-
6. **One assertion focus** - Each test verifies one behavior
|
|
334
|
-
7. **Keep tests independent** - No shared state between tests
|
|
335
|
-
8. **Test at boundaries** - Min/max values, length limits
|
|
328
|
+
1. **Test happy paths, edge cases, and errors** - Cover expected, boundary, and failure scenarios
|
|
329
|
+
2. **Use mocks** - Isolate from external dependencies
|
|
330
|
+
3. **Descriptive test names** - Explain what's being tested
|
|
331
|
+
4. **One assertion focus** - Each test verifies one behavior
|
|
332
|
+
5. **Keep tests independent** - No shared state between tests
|
package/xanoscript_docs/tools.md
CHANGED
|
@@ -62,20 +62,15 @@ tool "get_user_by_email" {
|
|
|
62
62
|
|
|
63
63
|
## Input Block
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
For complete type reference, use `xanoscript_docs({ keyword: "input" })`. For tools, input `description` fields are sent to the AI, so write them clearly:
|
|
66
66
|
|
|
67
67
|
```xs
|
|
68
68
|
input {
|
|
69
|
-
int order_id {
|
|
70
|
-
description = "The unique order ID to look up"
|
|
71
|
-
}
|
|
69
|
+
int order_id { description = "The unique order ID to look up" }
|
|
72
70
|
enum status {
|
|
73
71
|
description = "New status to set"
|
|
74
72
|
values = ["pending", "processing", "shipped", "delivered"]
|
|
75
73
|
}
|
|
76
|
-
text reason? {
|
|
77
|
-
description = "Optional reason for the status change"
|
|
78
|
-
}
|
|
79
74
|
}
|
|
80
75
|
```
|
|
81
76
|
|
|
@@ -299,7 +294,4 @@ tool "cancel_order" {
|
|
|
299
294
|
2. **Describe all inputs** - Help AI construct valid requests
|
|
300
295
|
3. **Use enums for fixed options** - Reduces AI errors
|
|
301
296
|
4. **Keep tools focused** - One task per tool
|
|
302
|
-
5. **
|
|
303
|
-
6. **Validate inputs** - Use filters and preconditions
|
|
304
|
-
7. **Limit response size** - Don't return huge datasets
|
|
305
|
-
8. **Use composition** - Call other tools for complex operations
|
|
297
|
+
5. **Limit response size** - Don't return huge datasets
|
|
@@ -0,0 +1,532 @@
|
|
|
1
|
+
---
|
|
2
|
+
applyTo: "triggers/**/*.xs"
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Triggers
|
|
6
|
+
|
|
7
|
+
Event-driven handlers that execute in response to system events. Triggers allow you to react to database changes, real-time messages, workspace events, agent connections, and MCP server tool calls.
|
|
8
|
+
|
|
9
|
+
## Quick Reference
|
|
10
|
+
|
|
11
|
+
| Trigger Type | Purpose | Required Clauses |
|
|
12
|
+
|--------------|---------|------------------|
|
|
13
|
+
| `table_trigger` | React to database table changes | `table`, `input`, `stack` |
|
|
14
|
+
| `realtime_trigger` | Handle real-time channel events | `channel`, `input`, `stack`, `response` |
|
|
15
|
+
| `workspace_trigger` | React to branch lifecycle events | `input`, `stack` |
|
|
16
|
+
| `agent_trigger` | Handle AI agent connections | `agent`, `input`, `stack`, `response` |
|
|
17
|
+
| `mcp_server_trigger` | Handle MCP server tool calls | `mcp_server`, `input`, `stack`, `response` |
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Table Trigger
|
|
22
|
+
|
|
23
|
+
Executes when database table records are inserted, updated, deleted, or truncated.
|
|
24
|
+
|
|
25
|
+
### Syntax
|
|
26
|
+
|
|
27
|
+
```xs
|
|
28
|
+
table_trigger "<name>" {
|
|
29
|
+
table = "<table_name>"
|
|
30
|
+
actions = {insert: true, update: true, delete: true, truncate: false}
|
|
31
|
+
datasources = ["datasource1", "datasource2"]
|
|
32
|
+
active = true
|
|
33
|
+
description = "Description of this trigger"
|
|
34
|
+
tags = ["tag1", "tag2"]
|
|
35
|
+
|
|
36
|
+
input {
|
|
37
|
+
# Define input parameters
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
stack {
|
|
41
|
+
# Logic to execute when triggered
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
history = 100
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Required Clauses
|
|
49
|
+
|
|
50
|
+
| Clause | Description |
|
|
51
|
+
|--------|-------------|
|
|
52
|
+
| `table` | The database table name to monitor |
|
|
53
|
+
| `input` | Input parameter definitions |
|
|
54
|
+
| `stack` | Logic to execute when triggered |
|
|
55
|
+
|
|
56
|
+
### Optional Clauses
|
|
57
|
+
|
|
58
|
+
| Clause | Type | Description |
|
|
59
|
+
|--------|------|-------------|
|
|
60
|
+
| `actions` | object | Which operations trigger execution |
|
|
61
|
+
| `active` | boolean | Enable/disable the trigger |
|
|
62
|
+
| `datasources` | array | List of datasources to apply trigger to |
|
|
63
|
+
| `description` | string | Human-readable description |
|
|
64
|
+
| `history` | integer/string | History retention setting |
|
|
65
|
+
| `tags` | array | Tags for organization |
|
|
66
|
+
|
|
67
|
+
### Actions
|
|
68
|
+
|
|
69
|
+
| Action | Description |
|
|
70
|
+
|--------|-------------|
|
|
71
|
+
| `insert` | Trigger on new record creation |
|
|
72
|
+
| `update` | Trigger on record modification |
|
|
73
|
+
| `delete` | Trigger on record deletion |
|
|
74
|
+
| `truncate` | Trigger when table is truncated |
|
|
75
|
+
|
|
76
|
+
### Example
|
|
77
|
+
|
|
78
|
+
```xs
|
|
79
|
+
table_trigger "audit_user_changes" {
|
|
80
|
+
table = "user"
|
|
81
|
+
actions = {insert: true, update: true, delete: true, truncate: false}
|
|
82
|
+
active = true
|
|
83
|
+
description = "Log all changes to user records"
|
|
84
|
+
datasources = ["main_db"]
|
|
85
|
+
|
|
86
|
+
input {
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
stack {
|
|
90
|
+
db.add "audit_log" {
|
|
91
|
+
data = {
|
|
92
|
+
table_name: "user",
|
|
93
|
+
action: $trigger.action,
|
|
94
|
+
record_id: $trigger.record.id,
|
|
95
|
+
timestamp: now
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
history = 100
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Realtime Trigger
|
|
107
|
+
|
|
108
|
+
Handles events from real-time channels, such as client joins or messages.
|
|
109
|
+
|
|
110
|
+
### Syntax
|
|
111
|
+
|
|
112
|
+
```xs
|
|
113
|
+
realtime_trigger "<name>" {
|
|
114
|
+
channel = "<channel_name>"
|
|
115
|
+
actions = {join: true, message: true}
|
|
116
|
+
active = true
|
|
117
|
+
description = "Description of this trigger"
|
|
118
|
+
tags = ["tag1", "tag2"]
|
|
119
|
+
|
|
120
|
+
input {
|
|
121
|
+
# Define input parameters
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
stack {
|
|
125
|
+
# Logic to execute when triggered
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
response = $result
|
|
129
|
+
|
|
130
|
+
history = 100
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Required Clauses
|
|
135
|
+
|
|
136
|
+
| Clause | Description |
|
|
137
|
+
|--------|-------------|
|
|
138
|
+
| `channel` | The real-time channel to monitor |
|
|
139
|
+
| `input` | Input parameter definitions |
|
|
140
|
+
| `stack` | Logic to execute when triggered |
|
|
141
|
+
| `response` | Value to return to the client |
|
|
142
|
+
|
|
143
|
+
### Optional Clauses
|
|
144
|
+
|
|
145
|
+
| Clause | Type | Description |
|
|
146
|
+
|--------|------|-------------|
|
|
147
|
+
| `actions` | object | Which events trigger execution |
|
|
148
|
+
| `active` | boolean | Enable/disable the trigger |
|
|
149
|
+
| `description` | string | Human-readable description |
|
|
150
|
+
| `history` | integer/string | History retention setting |
|
|
151
|
+
| `tags` | array | Tags for organization |
|
|
152
|
+
|
|
153
|
+
### Actions
|
|
154
|
+
|
|
155
|
+
| Action | Description |
|
|
156
|
+
|--------|-------------|
|
|
157
|
+
| `join` | Trigger when a client joins the channel |
|
|
158
|
+
| `message` | Trigger when a message is received |
|
|
159
|
+
|
|
160
|
+
### Example
|
|
161
|
+
|
|
162
|
+
```xs
|
|
163
|
+
realtime_trigger "chat_message_handler" {
|
|
164
|
+
channel = "chat_room"
|
|
165
|
+
actions = {join: true, message: true}
|
|
166
|
+
active = true
|
|
167
|
+
description = "Handle chat room messages and joins"
|
|
168
|
+
|
|
169
|
+
input {
|
|
170
|
+
text message filters=trim
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
stack {
|
|
174
|
+
conditional {
|
|
175
|
+
if ($trigger.action == "join") {
|
|
176
|
+
var $welcome { value = "Welcome to the chat!" }
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
db.add "chat_message" {
|
|
180
|
+
data = {
|
|
181
|
+
channel: "chat_room",
|
|
182
|
+
user_id: $auth.id,
|
|
183
|
+
message: $input.message,
|
|
184
|
+
timestamp: now
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
var $welcome { value = null }
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
response = {status: "ok", welcome: $welcome}
|
|
193
|
+
|
|
194
|
+
history = false
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## Workspace Trigger
|
|
201
|
+
|
|
202
|
+
Executes in response to workspace branch lifecycle events.
|
|
203
|
+
|
|
204
|
+
### Syntax
|
|
205
|
+
|
|
206
|
+
```xs
|
|
207
|
+
workspace_trigger "<name>" {
|
|
208
|
+
actions = {branch_new: true, branch_merge: true, branch_live: true}
|
|
209
|
+
active = true
|
|
210
|
+
description = "Description of this trigger"
|
|
211
|
+
tags = ["tag1", "tag2"]
|
|
212
|
+
|
|
213
|
+
input {
|
|
214
|
+
# Define input parameters
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
stack {
|
|
218
|
+
# Logic to execute when triggered
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
history = 100
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Required Clauses
|
|
226
|
+
|
|
227
|
+
| Clause | Description |
|
|
228
|
+
|--------|-------------|
|
|
229
|
+
| `input` | Input parameter definitions |
|
|
230
|
+
| `stack` | Logic to execute when triggered |
|
|
231
|
+
|
|
232
|
+
### Optional Clauses
|
|
233
|
+
|
|
234
|
+
| Clause | Type | Description |
|
|
235
|
+
|--------|------|-------------|
|
|
236
|
+
| `actions` | object | Which branch events trigger execution |
|
|
237
|
+
| `active` | boolean | Enable/disable the trigger |
|
|
238
|
+
| `description` | string | Human-readable description |
|
|
239
|
+
| `history` | integer/string | History retention setting |
|
|
240
|
+
| `tags` | array | Tags for organization |
|
|
241
|
+
|
|
242
|
+
### Actions
|
|
243
|
+
|
|
244
|
+
| Action | Description |
|
|
245
|
+
|--------|-------------|
|
|
246
|
+
| `branch_new` | Trigger when a new branch is created |
|
|
247
|
+
| `branch_merge` | Trigger when a branch is merged |
|
|
248
|
+
| `branch_live` | Trigger when a branch goes live |
|
|
249
|
+
|
|
250
|
+
### Example
|
|
251
|
+
|
|
252
|
+
```xs
|
|
253
|
+
workspace_trigger "branch_notification" {
|
|
254
|
+
actions = {branch_new: true, branch_merge: true, branch_live: true}
|
|
255
|
+
active = true
|
|
256
|
+
description = "Send notifications on branch events"
|
|
257
|
+
tags = ["devops", "notifications"]
|
|
258
|
+
|
|
259
|
+
input {
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
stack {
|
|
263
|
+
util.send_email {
|
|
264
|
+
service_provider = "resend"
|
|
265
|
+
api_key = $env.RESEND_API_KEY
|
|
266
|
+
to = "team@example.com"
|
|
267
|
+
from = "system@example.com"
|
|
268
|
+
subject = "Branch Event: " ~ $trigger.action
|
|
269
|
+
message = "Branch '" ~ $trigger.branch_name ~ "' event: " ~ $trigger.action
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
history = false
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
## Agent Trigger
|
|
280
|
+
|
|
281
|
+
Handles connections and interactions with AI agents.
|
|
282
|
+
|
|
283
|
+
### Syntax
|
|
284
|
+
|
|
285
|
+
```xs
|
|
286
|
+
agent_trigger "<name>" {
|
|
287
|
+
agent = "<agent_name>"
|
|
288
|
+
actions = {connection: true}
|
|
289
|
+
active = true
|
|
290
|
+
description = "Description of this trigger"
|
|
291
|
+
docs = "Extended documentation for the trigger"
|
|
292
|
+
tags = ["tag1", "tag2"]
|
|
293
|
+
|
|
294
|
+
input {
|
|
295
|
+
# Define input parameters
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
stack {
|
|
299
|
+
# Logic to execute when triggered
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
response = $result
|
|
303
|
+
|
|
304
|
+
history = "inherit"
|
|
305
|
+
}
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### Required Clauses
|
|
309
|
+
|
|
310
|
+
| Clause | Description |
|
|
311
|
+
|--------|-------------|
|
|
312
|
+
| `agent` | The AI agent name this trigger handles |
|
|
313
|
+
| `input` | Input parameter definitions |
|
|
314
|
+
| `stack` | Logic to execute when triggered |
|
|
315
|
+
| `response` | Value to return |
|
|
316
|
+
|
|
317
|
+
### Optional Clauses
|
|
318
|
+
|
|
319
|
+
| Clause | Type | Description |
|
|
320
|
+
|--------|------|-------------|
|
|
321
|
+
| `actions` | object | Which agent events trigger execution |
|
|
322
|
+
| `active` | boolean | Enable/disable the trigger |
|
|
323
|
+
| `description` | string | Short description |
|
|
324
|
+
| `docs` | string | Extended documentation |
|
|
325
|
+
| `history` | integer/string/boolean | History retention setting |
|
|
326
|
+
| `tags` | array | Tags for organization |
|
|
327
|
+
|
|
328
|
+
### Actions
|
|
329
|
+
|
|
330
|
+
| Action | Description |
|
|
331
|
+
|--------|-------------|
|
|
332
|
+
| `connection` | Trigger on agent connection events |
|
|
333
|
+
|
|
334
|
+
### Example
|
|
335
|
+
|
|
336
|
+
```xs
|
|
337
|
+
agent_trigger "assistant_handler" {
|
|
338
|
+
agent = "customer_assistant"
|
|
339
|
+
actions = {connection: true}
|
|
340
|
+
active = true
|
|
341
|
+
description = "Handle customer assistant agent connections"
|
|
342
|
+
docs = "This trigger initializes the customer context when the agent connects"
|
|
343
|
+
|
|
344
|
+
input {
|
|
345
|
+
text session_id filters=trim
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
stack {
|
|
349
|
+
db.get "customer" {
|
|
350
|
+
field_name = "session_id"
|
|
351
|
+
field_value = $input.session_id
|
|
352
|
+
} as $customer
|
|
353
|
+
|
|
354
|
+
var $context {
|
|
355
|
+
value = {
|
|
356
|
+
customer_name: $customer.name,
|
|
357
|
+
customer_tier: $customer.tier,
|
|
358
|
+
history: $customer.support_history
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
response = $context
|
|
364
|
+
|
|
365
|
+
history = "inherit"
|
|
366
|
+
}
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
---
|
|
370
|
+
|
|
371
|
+
## MCP Server Trigger
|
|
372
|
+
|
|
373
|
+
Handles tool calls from MCP (Model Context Protocol) servers.
|
|
374
|
+
|
|
375
|
+
### Syntax
|
|
376
|
+
|
|
377
|
+
```xs
|
|
378
|
+
mcp_server_trigger "<name>" {
|
|
379
|
+
mcp_server = "<server_name>"
|
|
380
|
+
actions = {connection: true}
|
|
381
|
+
active = true
|
|
382
|
+
description = "Description of this trigger"
|
|
383
|
+
tags = ["tag1", "tag2"]
|
|
384
|
+
|
|
385
|
+
input {
|
|
386
|
+
# Define input parameters
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
stack {
|
|
390
|
+
# Logic to execute when triggered
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
response = $result
|
|
394
|
+
|
|
395
|
+
history = false
|
|
396
|
+
}
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
### Required Clauses
|
|
400
|
+
|
|
401
|
+
| Clause | Description |
|
|
402
|
+
|--------|-------------|
|
|
403
|
+
| `mcp_server` | The MCP server name this trigger handles |
|
|
404
|
+
| `input` | Input parameter definitions |
|
|
405
|
+
| `stack` | Logic to execute when triggered |
|
|
406
|
+
| `response` | Value to return to the MCP client |
|
|
407
|
+
|
|
408
|
+
### Optional Clauses
|
|
409
|
+
|
|
410
|
+
| Clause | Type | Description |
|
|
411
|
+
|--------|------|-------------|
|
|
412
|
+
| `actions` | object | Which MCP events trigger execution |
|
|
413
|
+
| `active` | boolean | Enable/disable the trigger |
|
|
414
|
+
| `description` | string | Human-readable description |
|
|
415
|
+
| `history` | integer/string/boolean | History retention setting |
|
|
416
|
+
| `tags` | array | Tags for organization |
|
|
417
|
+
|
|
418
|
+
### Actions
|
|
419
|
+
|
|
420
|
+
| Action | Description |
|
|
421
|
+
|--------|-------------|
|
|
422
|
+
| `connection` | Trigger on MCP connection events (required) |
|
|
423
|
+
|
|
424
|
+
### Example
|
|
425
|
+
|
|
426
|
+
```xs
|
|
427
|
+
mcp_server_trigger "database_tool_handler" {
|
|
428
|
+
mcp_server = "database_tools"
|
|
429
|
+
actions = {connection: true}
|
|
430
|
+
active = true
|
|
431
|
+
description = "Handle database tool calls from MCP clients"
|
|
432
|
+
tags = ["mcp", "database"]
|
|
433
|
+
|
|
434
|
+
input {
|
|
435
|
+
text operation filters=trim
|
|
436
|
+
object params
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
stack {
|
|
440
|
+
conditional {
|
|
441
|
+
if ($input.operation == "query") {
|
|
442
|
+
db.query $input.params.table {
|
|
443
|
+
where = $input.params.where
|
|
444
|
+
} as $result
|
|
445
|
+
}
|
|
446
|
+
elseif ($input.operation == "insert") {
|
|
447
|
+
db.add $input.params.table {
|
|
448
|
+
data = $input.params.data
|
|
449
|
+
} as $result
|
|
450
|
+
}
|
|
451
|
+
else {
|
|
452
|
+
var $result { value = {error: "Unknown operation"} }
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
response = $result
|
|
458
|
+
|
|
459
|
+
history = false
|
|
460
|
+
}
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
---
|
|
464
|
+
|
|
465
|
+
## Common Patterns
|
|
466
|
+
|
|
467
|
+
### Error Handling in Triggers
|
|
468
|
+
|
|
469
|
+
```xs
|
|
470
|
+
table_trigger "safe_audit" {
|
|
471
|
+
table = "sensitive_data"
|
|
472
|
+
actions = {insert: true, update: true, delete: true, truncate: false}
|
|
473
|
+
|
|
474
|
+
input {
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
stack {
|
|
478
|
+
try_catch {
|
|
479
|
+
try {
|
|
480
|
+
db.add "audit_log" {
|
|
481
|
+
data = {
|
|
482
|
+
action: $trigger.action,
|
|
483
|
+
timestamp: now
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
catch {
|
|
488
|
+
debug.log { value = "Audit logging failed" }
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
### Conditional Trigger Logic
|
|
496
|
+
|
|
497
|
+
```xs
|
|
498
|
+
table_trigger "conditional_notification" {
|
|
499
|
+
table = "order"
|
|
500
|
+
actions = {insert: true, update: false, delete: false, truncate: false}
|
|
501
|
+
|
|
502
|
+
input {
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
stack {
|
|
506
|
+
conditional {
|
|
507
|
+
if ($trigger.record.total > 1000) {
|
|
508
|
+
util.send_email {
|
|
509
|
+
service_provider = "resend"
|
|
510
|
+
api_key = $env.RESEND_API_KEY
|
|
511
|
+
to = "sales@example.com"
|
|
512
|
+
from = "system@example.com"
|
|
513
|
+
subject = "High Value Order"
|
|
514
|
+
message = "Order #" ~ $trigger.record.id ~ " for $" ~ $trigger.record.total
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
---
|
|
523
|
+
|
|
524
|
+
## Best Practices
|
|
525
|
+
|
|
526
|
+
1. **Use descriptive names** - Indicate the event and action: `user_audit_log`, `chat_message_handler`
|
|
527
|
+
2. **Handle errors gracefully** - Use try_catch to prevent trigger failures from affecting the main operation
|
|
528
|
+
3. **Keep triggers lightweight** - Offload heavy processing to functions or tasks
|
|
529
|
+
4. **Set appropriate history** - Use `history = false` for high-frequency triggers to save storage
|
|
530
|
+
5. **Use tags** - Organize triggers with meaningful tags for easier management
|
|
531
|
+
6. **Document with description** - Always provide a description explaining the trigger's purpose
|
|
532
|
+
7. **Test thoroughly** - Triggers execute automatically, so ensure they handle edge cases
|
package/xanoscript_docs/types.md
CHANGED
|
@@ -268,19 +268,12 @@ input {
|
|
|
268
268
|
|
|
269
269
|
## Validation with Preconditions
|
|
270
270
|
|
|
271
|
-
For complex validation beyond filters:
|
|
271
|
+
For complex validation beyond filters, use preconditions. For complete error handling reference, use `xanoscript_docs({ keyword: "syntax" })`.
|
|
272
272
|
|
|
273
273
|
```xs
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
error = "Start date must be before end date"
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
precondition ($input.password == $input.confirm_password) {
|
|
281
|
-
error_type = "inputerror"
|
|
282
|
-
error = "Passwords must match"
|
|
283
|
-
}
|
|
274
|
+
precondition ($input.start_date < $input.end_date) {
|
|
275
|
+
error_type = "inputerror"
|
|
276
|
+
error = "Start date must be before end date"
|
|
284
277
|
}
|
|
285
278
|
```
|
|
286
279
|
|
|
@@ -290,8 +283,5 @@ stack {
|
|
|
290
283
|
|
|
291
284
|
1. **Always specify types** - Never leave inputs untyped
|
|
292
285
|
2. **Use filters first** - Prefer declarative filters over stack validation
|
|
293
|
-
3. **
|
|
294
|
-
4. **
|
|
295
|
-
5. **Use defaults sparingly** - Make requirements explicit
|
|
296
|
-
6. **Validate at boundaries** - Validate user input, trust internal calls
|
|
297
|
-
7. **Limit nesting depth** - Keep object schemas 2-3 levels max
|
|
286
|
+
3. **Mark sensitive data** - Use `sensitive = true` for PII/credentials
|
|
287
|
+
4. **Validate at boundaries** - Validate user input, trust internal calls
|
package/xanoscript_docs/plan.md
DELETED
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
# XanoScript AI Documentation v2 - Implementation Plan
|
|
2
|
-
|
|
3
|
-
## Design Principles
|
|
4
|
-
|
|
5
|
-
### AI-First Documentation Goals
|
|
6
|
-
1. **Scannable** - AI can quickly locate relevant syntax/patterns
|
|
7
|
-
2. **Self-contained** - Each doc has everything needed for its topic
|
|
8
|
-
3. **Pattern-consistent** - Identical structure across all docs
|
|
9
|
-
4. **Minimal but complete** - Not verbose, but covers all cases
|
|
10
|
-
5. **Examples inline** - Code immediately follows syntax it demonstrates
|
|
11
|
-
|
|
12
|
-
### Document Structure Template
|
|
13
|
-
Every doc follows this structure:
|
|
14
|
-
```
|
|
15
|
-
---
|
|
16
|
-
applyTo: "<glob pattern>"
|
|
17
|
-
---
|
|
18
|
-
|
|
19
|
-
# <Topic>
|
|
20
|
-
|
|
21
|
-
## Quick Reference
|
|
22
|
-
<Table or code block with syntax summary>
|
|
23
|
-
|
|
24
|
-
## Overview
|
|
25
|
-
<1-2 paragraph explanation>
|
|
26
|
-
|
|
27
|
-
## <Concept 1>
|
|
28
|
-
### Syntax
|
|
29
|
-
### Example
|
|
30
|
-
### Notes
|
|
31
|
-
|
|
32
|
-
## <Concept 2>
|
|
33
|
-
...
|
|
34
|
-
|
|
35
|
-
## Best Practices
|
|
36
|
-
<Bullet list>
|
|
37
|
-
|
|
38
|
-
## Common Patterns
|
|
39
|
-
<Real-world usage patterns>
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
---
|
|
43
|
-
|
|
44
|
-
## Proposed File Structure
|
|
45
|
-
|
|
46
|
-
### Core (Required for any XanoScript work)
|
|
47
|
-
| File | Purpose | Source Files |
|
|
48
|
-
|------|---------|--------------|
|
|
49
|
-
| `README.md` | Overview, workspace structure, getting started | README.md, workspace.md |
|
|
50
|
-
| `syntax.md` | Expressions, operators, filters | expression_guideline.md, query_filter.md |
|
|
51
|
-
| `types.md` | Data types, input blocks, validation | input_guideline.md, functions.md (input section) |
|
|
52
|
-
|
|
53
|
-
### Primary Constructs
|
|
54
|
-
| File | Purpose | Source Files |
|
|
55
|
-
|------|---------|--------------|
|
|
56
|
-
| `tables.md` | Database schemas, indexes, relationships | table_guideline.md, table_examples.md |
|
|
57
|
-
| `functions.md` | Reusable function stacks | function_guideline.md, function_examples.md |
|
|
58
|
-
| `apis.md` | HTTP API endpoints | api_query_guideline.md, api_query_examples.md |
|
|
59
|
-
| `tasks.md` | Scheduled jobs | task_guideline.md, task_examples.md |
|
|
60
|
-
| `database.md` | All db.* operations | db_query_guideline.md, functions.md (db section) |
|
|
61
|
-
|
|
62
|
-
### AI Integration
|
|
63
|
-
| File | Purpose | Source Files |
|
|
64
|
-
|------|---------|--------------|
|
|
65
|
-
| `agents.md` | AI agents, LLM providers | agent_guideline.md, agent_examples.md |
|
|
66
|
-
| `tools.md` | AI tools for agents/MCP | tool_guideline.md, tool_examples.md |
|
|
67
|
-
| `mcp-servers.md` | MCP server configuration | mcp_server_guideline.md, mcp_server_examples.md |
|
|
68
|
-
|
|
69
|
-
### Advanced Features
|
|
70
|
-
| File | Purpose | Source Files |
|
|
71
|
-
|------|---------|--------------|
|
|
72
|
-
| `testing.md` | Unit tests, mocks, assertions | unit_testing_guideline.md |
|
|
73
|
-
| `integrations.md` | Cloud, Redis, storage, security | functions.md (cloud/redis/security sections) |
|
|
74
|
-
| `frontend.md` | Static frontend, Lovable migration | frontend_guideline.md, build_from_lovable.md |
|
|
75
|
-
| `ephemeral.md` | Ephemeral services and jobs | ephemeral_environment_guideline.md |
|
|
76
|
-
|
|
77
|
-
### Reference (Optional)
|
|
78
|
-
| File | Purpose | Source Files |
|
|
79
|
-
|------|---------|--------------|
|
|
80
|
-
| `tips.md` | Tips, tricks, gotchas | tips_and_tricks.md |
|
|
81
|
-
|
|
82
|
-
---
|
|
83
|
-
|
|
84
|
-
## Content Reduction Strategy
|
|
85
|
-
|
|
86
|
-
### V1 Verbosity Issues
|
|
87
|
-
1. **Redundant examples** - Multiple examples showing same pattern
|
|
88
|
-
2. **Explanation repetition** - Same concept explained in guideline AND examples
|
|
89
|
-
3. **Over-commented code** - Examples have excessive inline comments
|
|
90
|
-
4. **Separate files** - guideline.md + examples.md = duplication
|
|
91
|
-
|
|
92
|
-
### V2 Approach
|
|
93
|
-
1. **One canonical example** per feature (not 3-5)
|
|
94
|
-
2. **Table-based syntax reference** - Quick scan, no prose
|
|
95
|
-
3. **Inline examples** - Example immediately after syntax
|
|
96
|
-
4. **Comments only for non-obvious** - Trust the reader
|
|
97
|
-
|
|
98
|
-
### Example Transformation
|
|
99
|
-
|
|
100
|
-
**V1 Style (verbose):**
|
|
101
|
-
```xs
|
|
102
|
-
// This function calculates the total cost
|
|
103
|
-
// by multiplying quantity by price per item
|
|
104
|
-
// and returns the result
|
|
105
|
-
function "maths/calculate_total" {
|
|
106
|
-
description = "Calculate the total cost based on quantity and price per item"
|
|
107
|
-
|
|
108
|
-
input {
|
|
109
|
-
int quantity filters=min:0 {
|
|
110
|
-
description = "Number of items"
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
decimal price_per_item filters=min:0.01 {
|
|
114
|
-
description = "Price for each item"
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
stack {
|
|
119
|
-
var $total {
|
|
120
|
-
value = 0
|
|
121
|
-
description = "Initialize total"
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
math.add $total {
|
|
125
|
-
value = $input.quantity * $input.price_per_item
|
|
126
|
-
description = "Calculate total"
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
response = $total
|
|
131
|
-
}
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
**V2 Style (minimal):**
|
|
135
|
-
```xs
|
|
136
|
-
function "calculate_total" {
|
|
137
|
-
input {
|
|
138
|
-
int quantity filters=min:0
|
|
139
|
-
decimal price filters=min:0.01
|
|
140
|
-
}
|
|
141
|
-
stack {
|
|
142
|
-
var $total { value = $input.quantity * $input.price }
|
|
143
|
-
}
|
|
144
|
-
response = $total
|
|
145
|
-
}
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
---
|
|
149
|
-
|
|
150
|
-
## Estimated Reduction
|
|
151
|
-
|
|
152
|
-
| Metric | V1 | V2 Target | Reduction |
|
|
153
|
-
|--------|-----|-----------|-----------|
|
|
154
|
-
| Files | 27 | 14 | ~48% |
|
|
155
|
-
| Total Lines | ~5000 | ~2000 | ~60% |
|
|
156
|
-
| Avg File Size | 185 lines | 140 lines | ~25% |
|
|
157
|
-
|
|
158
|
-
---
|
|
159
|
-
|
|
160
|
-
## Implementation Order
|
|
161
|
-
|
|
162
|
-
### Phase 1: Foundation
|
|
163
|
-
1. README.md - Workspace overview
|
|
164
|
-
2. syntax.md - All expressions and filters
|
|
165
|
-
3. types.md - Data types and inputs
|
|
166
|
-
|
|
167
|
-
### Phase 2: Core Constructs
|
|
168
|
-
4. tables.md - Database tables
|
|
169
|
-
5. functions.md - Functions
|
|
170
|
-
6. apis.md - API endpoints
|
|
171
|
-
7. tasks.md - Scheduled tasks
|
|
172
|
-
8. database.md - DB operations
|
|
173
|
-
|
|
174
|
-
### Phase 3: AI Features
|
|
175
|
-
9. agents.md - AI agents
|
|
176
|
-
10. tools.md - AI tools
|
|
177
|
-
11. mcp-servers.md - MCP servers
|
|
178
|
-
|
|
179
|
-
### Phase 4: Advanced
|
|
180
|
-
12. testing.md - Unit testing
|
|
181
|
-
13. integrations.md - Cloud/Redis/Security
|
|
182
|
-
14. frontend.md - Frontend + Lovable
|
|
183
|
-
15. ephemeral.md - Ephemeral environments
|
|
184
|
-
|
|
185
|
-
---
|
|
186
|
-
|
|
187
|
-
## Questions Resolved
|
|
188
|
-
|
|
189
|
-
- [x] Structure: Consolidated (single file per concept)
|
|
190
|
-
- [x] Examples: Minimal (just enough to demonstrate)
|
|
191
|
-
- [x] Quick Reference: Yes (syntax cheatsheets at top)
|
|
192
|
-
- [x] Scope: Complete coverage (all features)
|