@xano/developer-mcp 1.0.20 → 1.0.21
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 +15 -0
- package/dist/templates/init-workspace.js +4 -4
- package/dist/templates/xanoscript-index.d.ts +3 -1
- package/dist/templates/xanoscript-index.js +54 -51
- package/dist/xanoscript_docs/README.md +51 -37
- package/dist/xanoscript_docs/apis.md +6 -3
- package/dist/xanoscript_docs/branch.md +239 -0
- package/dist/xanoscript_docs/functions.md +2 -2
- package/dist/xanoscript_docs/middleware.md +321 -0
- package/dist/xanoscript_docs/realtime.md +113 -1
- package/dist/xanoscript_docs/tools.md +1 -1
- package/dist/xanoscript_docs/types.md +25 -8
- package/dist/xanoscript_docs/workspace.md +209 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -134,6 +134,21 @@ const XANOSCRIPT_DOCS_V2 = {
|
|
|
134
134
|
applyTo: ["functions/**/*.xs", "apis/**/*.xs"],
|
|
135
135
|
description: "Streaming data from files, requests, and responses",
|
|
136
136
|
},
|
|
137
|
+
middleware: {
|
|
138
|
+
file: "middleware.md",
|
|
139
|
+
applyTo: ["middleware/**/*.xs"],
|
|
140
|
+
description: "Request/response interceptors for functions, queries, tasks, and tools",
|
|
141
|
+
},
|
|
142
|
+
branch: {
|
|
143
|
+
file: "branch.md",
|
|
144
|
+
applyTo: ["branch.xs"],
|
|
145
|
+
description: "Branch-level settings: middleware, history retention, visual styling",
|
|
146
|
+
},
|
|
147
|
+
workspace: {
|
|
148
|
+
file: "workspace.md",
|
|
149
|
+
applyTo: ["workspace.xs"],
|
|
150
|
+
description: "Workspace-level settings: environment variables, preferences, realtime",
|
|
151
|
+
},
|
|
137
152
|
};
|
|
138
153
|
// =============================================================================
|
|
139
154
|
// Path Resolution
|
|
@@ -260,10 +260,10 @@ const response = await fetch(
|
|
|
260
260
|
For writing XanoScript code, use:
|
|
261
261
|
|
|
262
262
|
- \`xanoscript_docs()\` - Full documentation index
|
|
263
|
-
- \`xanoscript_docs({
|
|
264
|
-
- \`xanoscript_docs({
|
|
265
|
-
- \`xanoscript_docs({
|
|
266
|
-
- \`xanoscript_docs({
|
|
263
|
+
- \`xanoscript_docs({ topic: "functions" })\` - Function syntax
|
|
264
|
+
- \`xanoscript_docs({ topic: "tables" })\` - Table schema syntax
|
|
265
|
+
- \`xanoscript_docs({ topic: "apis" })\` - API endpoint syntax
|
|
266
|
+
- \`xanoscript_docs({ topic: "syntax" })\` - Language reference
|
|
267
267
|
|
|
268
268
|
## Validating XanoScript
|
|
269
269
|
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Template for xanoscript_docs index documentation
|
|
3
3
|
* Edit this file to update the XanoScript documentation index
|
|
4
|
+
*
|
|
5
|
+
* NOTE: This template is currently unused. The actual documentation is served
|
|
6
|
+
* directly from the XANOSCRIPT_DOCS_V2 config in index.ts.
|
|
4
7
|
*/
|
|
5
8
|
export interface XanoscriptIndexParams {
|
|
6
9
|
version: string;
|
|
7
|
-
aliasLookup: Record<string, string[]>;
|
|
8
10
|
}
|
|
9
11
|
export declare function generateXanoscriptIndexTemplate(params: XanoscriptIndexParams): string;
|
|
@@ -1,69 +1,72 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Template for xanoscript_docs index documentation
|
|
3
3
|
* Edit this file to update the XanoScript documentation index
|
|
4
|
+
*
|
|
5
|
+
* NOTE: This template is currently unused. The actual documentation is served
|
|
6
|
+
* directly from the XANOSCRIPT_DOCS_V2 config in index.ts.
|
|
4
7
|
*/
|
|
5
8
|
export function generateXanoscriptIndexTemplate(params) {
|
|
6
|
-
const { version
|
|
7
|
-
const formatRow = (keyword, description) => {
|
|
8
|
-
const aliases = aliasLookup[keyword]?.slice(0, 3).join(", ") || "";
|
|
9
|
-
return `| \`${keyword}\` | ${aliases ? aliases : "-"} | ${description} |`;
|
|
10
|
-
};
|
|
9
|
+
const { version } = params;
|
|
11
10
|
return `# XanoScript Documentation Index
|
|
12
11
|
Version: ${version}
|
|
13
12
|
|
|
14
|
-
Use \`xanoscript_docs
|
|
13
|
+
Use \`xanoscript_docs({ topic: "<topic>" })\` to retrieve documentation.
|
|
15
14
|
|
|
16
|
-
## Core
|
|
17
|
-
|
|
15
|
+
## Core Language
|
|
16
|
+
| Topic | Description |
|
|
17
|
+
|-------|-------------|
|
|
18
|
+
| \`syntax\` | Expressions, operators, filters, system variables |
|
|
19
|
+
| \`types\` | Data types, validation, input blocks |
|
|
20
|
+
| \`functions\` | Reusable function stacks, async, loops |
|
|
21
|
+
| \`schema\` | Runtime schema parsing and validation |
|
|
18
22
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
${formatRow("tool", "AI-callable tools in `tools/`")}
|
|
27
|
-
${formatRow("agent", "AI agents in `agents/`")}
|
|
28
|
-
${formatRow("mcp_server", "MCP servers in `mcp_servers/`")}
|
|
23
|
+
## Data
|
|
24
|
+
| Topic | Description |
|
|
25
|
+
|-------|-------------|
|
|
26
|
+
| \`tables\` | Database schema definitions with indexes and relationships |
|
|
27
|
+
| \`database\` | All db.* operations: query, get, add, edit, patch, delete |
|
|
28
|
+
| \`addons\` | Reusable subqueries for fetching related data |
|
|
29
|
+
| \`streaming\` | Streaming data from files, requests, and responses |
|
|
29
30
|
|
|
30
|
-
##
|
|
31
|
-
|
|
31
|
+
## APIs & Endpoints
|
|
32
|
+
| Topic | Description |
|
|
33
|
+
|-------|-------------|
|
|
34
|
+
| \`apis\` | HTTP endpoint definitions with authentication and CRUD patterns |
|
|
35
|
+
| \`tasks\` | Scheduled and cron jobs |
|
|
36
|
+
| \`triggers\` | Event-driven handlers (table, realtime, workspace, agent, MCP) |
|
|
37
|
+
| \`realtime\` | Real-time channels and events for push updates |
|
|
32
38
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
${formatRow("query_filter", "WHERE clause and filter syntax")}
|
|
39
|
+
## AI & Agents
|
|
40
|
+
| Topic | Description |
|
|
41
|
+
|-------|-------------|
|
|
42
|
+
| \`agents\` | AI agent configuration with LLM providers and tools |
|
|
43
|
+
| \`tools\` | AI tools for agents and MCP servers |
|
|
44
|
+
| \`mcp-servers\` | MCP server definitions exposing tools |
|
|
40
45
|
|
|
41
|
-
##
|
|
42
|
-
|
|
46
|
+
## Integrations
|
|
47
|
+
| Topic | Description |
|
|
48
|
+
|-------|-------------|
|
|
49
|
+
| \`integrations\` | Cloud storage, Redis, security, and external APIs |
|
|
43
50
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
${formatRow("task_workflow", "AI workflow for creating tasks")}
|
|
51
|
+
## Configuration
|
|
52
|
+
| Topic | Description |
|
|
53
|
+
|-------|-------------|
|
|
54
|
+
| \`workspace\` | Workspace-level settings: environment variables, preferences, realtime |
|
|
55
|
+
| \`branch\` | Branch-level settings: middleware, history retention, visual styling |
|
|
56
|
+
| \`middleware\` | Request/response interceptors for functions, queries, tasks, and tools |
|
|
51
57
|
|
|
52
|
-
##
|
|
58
|
+
## Development
|
|
59
|
+
| Topic | Description |
|
|
60
|
+
|-------|-------------|
|
|
61
|
+
| \`testing\` | Unit tests, mocks, and assertions |
|
|
62
|
+
| \`debugging\` | Logging, inspecting, and debugging XanoScript execution |
|
|
63
|
+
| \`frontend\` | Static frontend development and deployment |
|
|
64
|
+
| \`run\` | Run job and service configurations for the Xano Job Runner |
|
|
53
65
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
${formatRow("lovable", "Building from Lovable-generated websites")}
|
|
60
|
-
${formatRow("performance", "Performance optimization best practices")}
|
|
61
|
-
${formatRow("realtime", "Real-time channels and events")}
|
|
62
|
-
${formatRow("schema", "Runtime schema parsing and validation")}
|
|
63
|
-
${formatRow("security", "Security best practices")}
|
|
64
|
-
${formatRow("streaming", "Streaming data from files and responses")}
|
|
65
|
-
${formatRow("testing", "Unit testing XanoScript code")}
|
|
66
|
-
${formatRow("tips", "Tips and tricks")}
|
|
67
|
-
${formatRow("run", "Run job and service configurations")}
|
|
66
|
+
## Best Practices
|
|
67
|
+
| Topic | Description |
|
|
68
|
+
|-------|-------------|
|
|
69
|
+
| \`performance\` | Performance optimization best practices |
|
|
70
|
+
| \`security\` | Security best practices for authentication and authorization |
|
|
68
71
|
`;
|
|
69
72
|
}
|
|
@@ -15,6 +15,10 @@ XanoScript is the declarative scripting language for [Xano](https://xano.com), a
|
|
|
15
15
|
| `tool` | `tools/**/*.xs` | Tools for AI agents |
|
|
16
16
|
| `mcp_server` | `mcp_servers/**/*.xs` | MCP server definitions |
|
|
17
17
|
| `addon` | `addons/*.xs` | Subqueries for related data |
|
|
18
|
+
| `middleware` | `middleware/**/*.xs` | Request/response interceptors |
|
|
19
|
+
| `branch` | `branch.xs` | Branch-level configuration |
|
|
20
|
+
| `workspace` | `workspace.xs` | Workspace-level configuration |
|
|
21
|
+
| `realtime_channel` | Configuration | Realtime channel settings |
|
|
18
22
|
|
|
19
23
|
**Important:** Each `.xs` file must contain exactly one definition. You cannot define multiple tables, functions, queries, or other constructs in a single file.
|
|
20
24
|
|
|
@@ -22,6 +26,8 @@ XanoScript is the declarative scripting language for [Xano](https://xano.com), a
|
|
|
22
26
|
|
|
23
27
|
```
|
|
24
28
|
project/
|
|
29
|
+
├── workspace.xs // Workspace configuration (env vars, preferences)
|
|
30
|
+
├── branch.xs // Branch configuration (middleware, history)
|
|
25
31
|
├── tables/ // Database table schemas
|
|
26
32
|
├── functions/ // Reusable functions (supports subfolders)
|
|
27
33
|
├── apis/
|
|
@@ -31,6 +37,7 @@ project/
|
|
|
31
37
|
├── agents/ // AI agents
|
|
32
38
|
├── tools/ // AI tools
|
|
33
39
|
├── mcp_servers/ // MCP server definitions
|
|
40
|
+
├── middleware/ // Request/response interceptors
|
|
34
41
|
├── addons/ // Query addons
|
|
35
42
|
├── static/ // Frontend files (HTML, CSS, JS)
|
|
36
43
|
└── run/ // Job and service configurations
|
|
@@ -103,54 +110,61 @@ This helps AI tools apply the correct documentation based on the file being edit
|
|
|
103
110
|
|
|
104
111
|
## Documentation Index
|
|
105
112
|
|
|
106
|
-
Use `xanoscript_docs({
|
|
113
|
+
Use `xanoscript_docs({ topic: "<topic>" })` to retrieve documentation.
|
|
107
114
|
|
|
108
115
|
### Core Language
|
|
109
|
-
| Topic |
|
|
110
|
-
|
|
111
|
-
|
|
|
112
|
-
|
|
|
113
|
-
|
|
|
114
|
-
|
|
|
116
|
+
| Topic | Description |
|
|
117
|
+
|-------|-------------|
|
|
118
|
+
| `syntax` | Expressions, operators, filters, system variables |
|
|
119
|
+
| `types` | Data types, validation, input blocks |
|
|
120
|
+
| `functions` | Reusable function stacks, async, loops |
|
|
121
|
+
| `schema` | Runtime schema parsing and validation |
|
|
115
122
|
|
|
116
123
|
### Data
|
|
117
|
-
| Topic |
|
|
118
|
-
|
|
119
|
-
|
|
|
120
|
-
|
|
|
121
|
-
|
|
|
122
|
-
|
|
|
124
|
+
| Topic | Description |
|
|
125
|
+
|-------|-------------|
|
|
126
|
+
| `tables` | Database schema definitions with indexes and relationships |
|
|
127
|
+
| `database` | All db.* operations: query, get, add, edit, patch, delete |
|
|
128
|
+
| `addons` | Reusable subqueries for fetching related data |
|
|
129
|
+
| `streaming` | Streaming data from files, requests, and responses |
|
|
123
130
|
|
|
124
131
|
### APIs & Endpoints
|
|
125
|
-
| Topic |
|
|
126
|
-
|
|
127
|
-
|
|
|
128
|
-
|
|
|
129
|
-
|
|
|
130
|
-
|
|
|
132
|
+
| Topic | Description |
|
|
133
|
+
|-------|-------------|
|
|
134
|
+
| `apis` | HTTP endpoint definitions with authentication and CRUD patterns |
|
|
135
|
+
| `tasks` | Scheduled and cron jobs |
|
|
136
|
+
| `triggers` | Event-driven handlers (table, realtime, workspace, agent, MCP) |
|
|
137
|
+
| `realtime` | Real-time channels and events for push updates |
|
|
131
138
|
|
|
132
139
|
### AI & Agents
|
|
133
|
-
| Topic |
|
|
134
|
-
|
|
135
|
-
|
|
|
136
|
-
|
|
|
137
|
-
|
|
|
140
|
+
| Topic | Description |
|
|
141
|
+
|-------|-------------|
|
|
142
|
+
| `agents` | AI agent configuration with LLM providers and tools |
|
|
143
|
+
| `tools` | AI tools for agents and MCP servers |
|
|
144
|
+
| `mcp-servers` | MCP server definitions exposing tools |
|
|
138
145
|
|
|
139
146
|
### Integrations
|
|
140
|
-
| Topic |
|
|
141
|
-
|
|
142
|
-
|
|
|
147
|
+
| Topic | Description |
|
|
148
|
+
|-------|-------------|
|
|
149
|
+
| `integrations` | Cloud storage, Redis, security, and external APIs |
|
|
150
|
+
|
|
151
|
+
### Configuration
|
|
152
|
+
| Topic | Description |
|
|
153
|
+
|-------|-------------|
|
|
154
|
+
| `workspace` | Workspace-level settings: environment variables, preferences, realtime |
|
|
155
|
+
| `branch` | Branch-level settings: middleware, history retention, visual styling |
|
|
156
|
+
| `middleware` | Request/response interceptors for functions, queries, tasks, and tools |
|
|
143
157
|
|
|
144
158
|
### Development
|
|
145
|
-
| Topic |
|
|
146
|
-
|
|
147
|
-
|
|
|
148
|
-
|
|
|
149
|
-
|
|
|
150
|
-
|
|
|
159
|
+
| Topic | Description |
|
|
160
|
+
|-------|-------------|
|
|
161
|
+
| `testing` | Unit tests, mocks, and assertions |
|
|
162
|
+
| `debugging` | Logging, inspecting, and debugging XanoScript execution |
|
|
163
|
+
| `frontend` | Static frontend development and deployment |
|
|
164
|
+
| `run` | Run job and service configurations for the Xano Job Runner |
|
|
151
165
|
|
|
152
166
|
### Best Practices
|
|
153
|
-
| Topic |
|
|
154
|
-
|
|
155
|
-
|
|
|
156
|
-
|
|
|
167
|
+
| Topic | Description |
|
|
168
|
+
|-------|-------------|
|
|
169
|
+
| `performance` | Performance optimization best practices |
|
|
170
|
+
| `security` | Security best practices for authentication and authorization |
|
|
@@ -86,7 +86,7 @@ query "products" verb=GET {
|
|
|
86
86
|
|
|
87
87
|
## Input Block
|
|
88
88
|
|
|
89
|
-
For complete type and filter reference, use `xanoscript_docs({
|
|
89
|
+
For complete type and filter reference, use `xanoscript_docs({ topic: "types" })`.
|
|
90
90
|
|
|
91
91
|
### Empty Input Blocks
|
|
92
92
|
|
|
@@ -345,11 +345,14 @@ stack {
|
|
|
345
345
|
|
|
346
346
|
## Error Handling
|
|
347
347
|
|
|
348
|
-
For complete error handling reference, use `xanoscript_docs({
|
|
348
|
+
For complete error handling reference, use `xanoscript_docs({ topic: "syntax" })`.
|
|
349
349
|
|
|
350
350
|
| Type | HTTP Status |
|
|
351
351
|
|------|-------------|
|
|
352
|
-
| `inputerror` | 400 |
|
|
352
|
+
| `inputerror` | 400 |
|
|
353
|
+
| `accessdenied` | 403 |
|
|
354
|
+
| `notfound` | 404 |
|
|
355
|
+
| `standard` | 500 |
|
|
353
356
|
|
|
354
357
|
---
|
|
355
358
|
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
---
|
|
2
|
+
applyTo: "branch.xs"
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Branch Configuration
|
|
6
|
+
|
|
7
|
+
Configure branch-level settings including middleware, history retention, and visual styling.
|
|
8
|
+
|
|
9
|
+
## Quick Reference
|
|
10
|
+
|
|
11
|
+
```xs
|
|
12
|
+
branch "<name>" {
|
|
13
|
+
color = "#hex"
|
|
14
|
+
description = "Branch description"
|
|
15
|
+
middleware = { ... }
|
|
16
|
+
history = { ... }
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### Attributes
|
|
21
|
+
| Attribute | Type | Required | Description |
|
|
22
|
+
|-----------|------|----------|-------------|
|
|
23
|
+
| `color` | text | Yes | Hex color code for branch identification |
|
|
24
|
+
| `description` | text | No | Human-readable branch description |
|
|
25
|
+
| `middleware` | object | No | Pre/post middleware configuration |
|
|
26
|
+
| `history` | object | No | Request history retention settings |
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Basic Structure
|
|
31
|
+
|
|
32
|
+
```xs
|
|
33
|
+
branch "production" {
|
|
34
|
+
color = "#22c55e"
|
|
35
|
+
description = "Production environment"
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Middleware Configuration
|
|
42
|
+
|
|
43
|
+
Configure middleware to run before (pre) and after (post) different construct types.
|
|
44
|
+
|
|
45
|
+
### Syntax
|
|
46
|
+
|
|
47
|
+
```xs
|
|
48
|
+
branch "production" {
|
|
49
|
+
color = "#22c55e"
|
|
50
|
+
|
|
51
|
+
middleware = {
|
|
52
|
+
function: {
|
|
53
|
+
pre: ["auth_check", "rate_limit"],
|
|
54
|
+
post: ["audit_log"]
|
|
55
|
+
},
|
|
56
|
+
query: {
|
|
57
|
+
pre: ["auth_check", "rate_limit"],
|
|
58
|
+
post: ["audit_log", "cache_response"]
|
|
59
|
+
},
|
|
60
|
+
task: {
|
|
61
|
+
pre: ["task_lock"],
|
|
62
|
+
post: ["task_cleanup"]
|
|
63
|
+
},
|
|
64
|
+
tool: {
|
|
65
|
+
pre: ["tool_auth"],
|
|
66
|
+
post: ["tool_log"]
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Middleware Targets
|
|
73
|
+
|
|
74
|
+
| Target | Description |
|
|
75
|
+
|--------|-------------|
|
|
76
|
+
| `function` | Applies to all function calls |
|
|
77
|
+
| `query` | Applies to all API endpoints |
|
|
78
|
+
| `task` | Applies to scheduled tasks |
|
|
79
|
+
| `tool` | Applies to AI agent tools |
|
|
80
|
+
|
|
81
|
+
### Pre vs Post Middleware
|
|
82
|
+
|
|
83
|
+
| Type | Execution | Use Cases |
|
|
84
|
+
|------|-----------|-----------|
|
|
85
|
+
| `pre` | Before main logic | Authentication, rate limiting, validation |
|
|
86
|
+
| `post` | After main logic | Logging, caching, response transformation |
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## History Configuration
|
|
91
|
+
|
|
92
|
+
Control how many historical executions are retained for debugging and auditing.
|
|
93
|
+
|
|
94
|
+
### Syntax
|
|
95
|
+
|
|
96
|
+
```xs
|
|
97
|
+
branch "production" {
|
|
98
|
+
color = "#22c55e"
|
|
99
|
+
|
|
100
|
+
history = {
|
|
101
|
+
function: 100,
|
|
102
|
+
query: 1000,
|
|
103
|
+
task: 100,
|
|
104
|
+
tool: 100,
|
|
105
|
+
trigger: 100,
|
|
106
|
+
middleware: 10
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### History Values
|
|
112
|
+
|
|
113
|
+
| Value | Description |
|
|
114
|
+
|-------|-------------|
|
|
115
|
+
| `false` | Disable history (no retention) |
|
|
116
|
+
| `10` | Keep last 10 executions |
|
|
117
|
+
| `100` | Keep last 100 executions |
|
|
118
|
+
| `1000` | Keep last 1000 executions |
|
|
119
|
+
| `10000` | Keep last 10000 executions |
|
|
120
|
+
| `"all"` | Keep all executions (use with caution) |
|
|
121
|
+
|
|
122
|
+
### History Targets
|
|
123
|
+
|
|
124
|
+
| Target | Description |
|
|
125
|
+
|--------|-------------|
|
|
126
|
+
| `function` | Function execution history |
|
|
127
|
+
| `query` | API endpoint request history |
|
|
128
|
+
| `task` | Scheduled task execution history |
|
|
129
|
+
| `tool` | AI tool invocation history |
|
|
130
|
+
| `trigger` | Trigger execution history |
|
|
131
|
+
| `middleware` | Middleware execution history |
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Common Patterns
|
|
136
|
+
|
|
137
|
+
### Development Branch
|
|
138
|
+
|
|
139
|
+
```xs
|
|
140
|
+
branch "development" {
|
|
141
|
+
color = "#3b82f6"
|
|
142
|
+
description = "Development environment with full debugging"
|
|
143
|
+
|
|
144
|
+
history = {
|
|
145
|
+
function: "all",
|
|
146
|
+
query: "all",
|
|
147
|
+
task: "all",
|
|
148
|
+
tool: "all",
|
|
149
|
+
trigger: "all",
|
|
150
|
+
middleware: "all"
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Staging Branch
|
|
156
|
+
|
|
157
|
+
```xs
|
|
158
|
+
branch "staging" {
|
|
159
|
+
color = "#f59e0b"
|
|
160
|
+
description = "Staging environment for testing"
|
|
161
|
+
|
|
162
|
+
middleware = {
|
|
163
|
+
query: {
|
|
164
|
+
pre: ["auth_check"],
|
|
165
|
+
post: ["audit_log"]
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
history = {
|
|
170
|
+
function: 1000,
|
|
171
|
+
query: 1000,
|
|
172
|
+
task: 100,
|
|
173
|
+
tool: 100,
|
|
174
|
+
trigger: 100,
|
|
175
|
+
middleware: 100
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Production Branch
|
|
181
|
+
|
|
182
|
+
```xs
|
|
183
|
+
branch "production" {
|
|
184
|
+
color = "#22c55e"
|
|
185
|
+
description = "Production environment"
|
|
186
|
+
|
|
187
|
+
middleware = {
|
|
188
|
+
function: {
|
|
189
|
+
pre: ["auth_check", "rate_limit"],
|
|
190
|
+
post: ["audit_log"]
|
|
191
|
+
},
|
|
192
|
+
query: {
|
|
193
|
+
pre: ["auth_check", "rate_limit", "security_check"],
|
|
194
|
+
post: ["audit_log", "cache_response"]
|
|
195
|
+
},
|
|
196
|
+
task: {
|
|
197
|
+
pre: ["task_lock"],
|
|
198
|
+
post: ["audit_log"]
|
|
199
|
+
},
|
|
200
|
+
tool: {
|
|
201
|
+
pre: ["auth_check"],
|
|
202
|
+
post: ["audit_log"]
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
history = {
|
|
207
|
+
function: 100,
|
|
208
|
+
query: 100,
|
|
209
|
+
task: 100,
|
|
210
|
+
tool: 100,
|
|
211
|
+
trigger: 100,
|
|
212
|
+
middleware: false
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## File Location
|
|
220
|
+
|
|
221
|
+
Branch configuration files are typically named `branch.xs` and placed at the workspace root or in a dedicated configuration directory.
|
|
222
|
+
|
|
223
|
+
```
|
|
224
|
+
project/
|
|
225
|
+
├── branch.xs // Branch configuration
|
|
226
|
+
├── tables/
|
|
227
|
+
├── functions/
|
|
228
|
+
└── apis/
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## Best Practices
|
|
234
|
+
|
|
235
|
+
1. **Use descriptive colors** - Green for production, blue for development, yellow for staging
|
|
236
|
+
2. **Limit production history** - Excessive history impacts performance and storage
|
|
237
|
+
3. **Apply security middleware in production** - Rate limiting, auth checks, audit logging
|
|
238
|
+
4. **Disable middleware history in production** - Reduces noise and storage
|
|
239
|
+
5. **Enable full history in development** - Aids debugging and testing
|
|
@@ -72,7 +72,7 @@ Reference with path: `function.run "math/add" { ... }`
|
|
|
72
72
|
|
|
73
73
|
## Input Block
|
|
74
74
|
|
|
75
|
-
For complete type and filter reference, use `xanoscript_docs({
|
|
75
|
+
For complete type and filter reference, use `xanoscript_docs({ topic: "types" })`.
|
|
76
76
|
|
|
77
77
|
```xs
|
|
78
78
|
input {
|
|
@@ -188,7 +188,7 @@ stack {
|
|
|
188
188
|
|
|
189
189
|
### Error Handling
|
|
190
190
|
|
|
191
|
-
For complete error handling reference (preconditions, try-catch, throw, early return), use `xanoscript_docs({
|
|
191
|
+
For complete error handling reference (preconditions, try-catch, throw, early return), use `xanoscript_docs({ topic: "syntax" })`.
|
|
192
192
|
|
|
193
193
|
---
|
|
194
194
|
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
---
|
|
2
|
+
applyTo: "middleware/**/*.xs"
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Middleware
|
|
6
|
+
|
|
7
|
+
Middleware intercepts and processes requests before and after your functions, queries, tasks, and tools execute.
|
|
8
|
+
|
|
9
|
+
## Quick Reference
|
|
10
|
+
|
|
11
|
+
```xs
|
|
12
|
+
middleware "<name>" {
|
|
13
|
+
description = "What this middleware does"
|
|
14
|
+
exception_policy = "silent" | "rethrow" | "critical"
|
|
15
|
+
response_strategy = "merge" | "replace"
|
|
16
|
+
input { ... }
|
|
17
|
+
stack { ... }
|
|
18
|
+
response = $result
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### Required Blocks
|
|
23
|
+
| Block | Purpose |
|
|
24
|
+
|-------|---------|
|
|
25
|
+
| `input` | Define parameters passed to middleware |
|
|
26
|
+
| `stack` | Processing logic |
|
|
27
|
+
| `response` | Output returned to caller |
|
|
28
|
+
|
|
29
|
+
### Optional Attributes
|
|
30
|
+
| Attribute | Values | Default | Description |
|
|
31
|
+
|-----------|--------|---------|-------------|
|
|
32
|
+
| `description` | text | - | Documents middleware purpose |
|
|
33
|
+
| `exception_policy` | `silent`, `rethrow`, `critical` | `rethrow` | How to handle errors |
|
|
34
|
+
| `response_strategy` | `merge`, `replace` | `merge` | How response combines with original |
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Basic Structure
|
|
39
|
+
|
|
40
|
+
```xs
|
|
41
|
+
middleware "log_request" {
|
|
42
|
+
description = "Logs all incoming requests"
|
|
43
|
+
|
|
44
|
+
input {
|
|
45
|
+
json request_data
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
stack {
|
|
49
|
+
debug.log {
|
|
50
|
+
value = {
|
|
51
|
+
timestamp: now,
|
|
52
|
+
data: $input.request_data
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
response = null
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Exception Policies
|
|
64
|
+
|
|
65
|
+
Control how middleware handles errors:
|
|
66
|
+
|
|
67
|
+
### silent
|
|
68
|
+
Errors are caught and ignored. Execution continues normally.
|
|
69
|
+
|
|
70
|
+
```xs
|
|
71
|
+
middleware "optional_enrichment" {
|
|
72
|
+
exception_policy = "silent"
|
|
73
|
+
|
|
74
|
+
input {
|
|
75
|
+
int user_id
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
stack {
|
|
79
|
+
// If this fails, request continues without enrichment
|
|
80
|
+
api.call "external_service" {
|
|
81
|
+
url = "https://api.example.com/enrich/" ~ $input.user_id
|
|
82
|
+
} as $enriched
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
response = $enriched
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### rethrow (default)
|
|
90
|
+
Errors are passed through to the caller. Standard error handling applies.
|
|
91
|
+
|
|
92
|
+
```xs
|
|
93
|
+
middleware "validate_token" {
|
|
94
|
+
exception_policy = "rethrow"
|
|
95
|
+
|
|
96
|
+
input {
|
|
97
|
+
text token
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
stack {
|
|
101
|
+
precondition ($input.token|strlen > 0) {
|
|
102
|
+
error_type = "accessdenied"
|
|
103
|
+
error = "Token required"
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
response = { valid: true }
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### critical
|
|
112
|
+
Errors are treated as critical failures. Request is immediately terminated.
|
|
113
|
+
|
|
114
|
+
```xs
|
|
115
|
+
middleware "security_check" {
|
|
116
|
+
exception_policy = "critical"
|
|
117
|
+
|
|
118
|
+
input {
|
|
119
|
+
text ip_address
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
stack {
|
|
123
|
+
db.query "blocked_ips" {
|
|
124
|
+
where = $db.blocked_ips.ip == $input.ip_address
|
|
125
|
+
return = { type: "exists" }
|
|
126
|
+
} as $is_blocked
|
|
127
|
+
|
|
128
|
+
precondition (!$is_blocked) {
|
|
129
|
+
error_type = "accessdenied"
|
|
130
|
+
error = "Access denied"
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
response = { allowed: true }
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## Response Strategies
|
|
141
|
+
|
|
142
|
+
Control how middleware response combines with the original response:
|
|
143
|
+
|
|
144
|
+
### merge (default)
|
|
145
|
+
Middleware response is merged with original response.
|
|
146
|
+
|
|
147
|
+
```xs
|
|
148
|
+
middleware "add_metadata" {
|
|
149
|
+
response_strategy = "merge"
|
|
150
|
+
|
|
151
|
+
input {
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
stack {
|
|
155
|
+
var $meta {
|
|
156
|
+
value = {
|
|
157
|
+
server_time: now,
|
|
158
|
+
version: "1.0.0"
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
response = { _meta: $meta }
|
|
164
|
+
}
|
|
165
|
+
// Original: { data: [...] }
|
|
166
|
+
// Result: { data: [...], _meta: { server_time: ..., version: "1.0.0" } }
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### replace
|
|
170
|
+
Middleware response completely replaces original response.
|
|
171
|
+
|
|
172
|
+
```xs
|
|
173
|
+
middleware "transform_response" {
|
|
174
|
+
response_strategy = "replace"
|
|
175
|
+
|
|
176
|
+
input {
|
|
177
|
+
json original_response
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
stack {
|
|
181
|
+
var $transformed {
|
|
182
|
+
value = {
|
|
183
|
+
success: true,
|
|
184
|
+
payload: $input.original_response
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
response = $transformed
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## Common Patterns
|
|
196
|
+
|
|
197
|
+
### Request Logging
|
|
198
|
+
|
|
199
|
+
```xs
|
|
200
|
+
middleware "audit_log" {
|
|
201
|
+
description = "Logs all API requests for audit trail"
|
|
202
|
+
exception_policy = "silent"
|
|
203
|
+
|
|
204
|
+
input {
|
|
205
|
+
text endpoint
|
|
206
|
+
text method
|
|
207
|
+
json request_body?
|
|
208
|
+
int user_id?
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
stack {
|
|
212
|
+
db.add "audit_log" {
|
|
213
|
+
data = {
|
|
214
|
+
endpoint: $input.endpoint,
|
|
215
|
+
method: $input.method,
|
|
216
|
+
request_body: $input.request_body,
|
|
217
|
+
user_id: $input.user_id,
|
|
218
|
+
ip_address: $env.$remote_ip,
|
|
219
|
+
created_at: now
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
response = null
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### Rate Limiting
|
|
229
|
+
|
|
230
|
+
```xs
|
|
231
|
+
middleware "rate_limit" {
|
|
232
|
+
description = "Enforces rate limits per user"
|
|
233
|
+
exception_policy = "rethrow"
|
|
234
|
+
|
|
235
|
+
input {
|
|
236
|
+
int user_id
|
|
237
|
+
int max_requests?=100
|
|
238
|
+
int window_seconds?=60
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
stack {
|
|
242
|
+
var $key { value = "ratelimit:" ~ $input.user_id }
|
|
243
|
+
|
|
244
|
+
redis.incr {
|
|
245
|
+
key = $key
|
|
246
|
+
} as $count
|
|
247
|
+
|
|
248
|
+
conditional {
|
|
249
|
+
if ($count == 1) {
|
|
250
|
+
redis.expire {
|
|
251
|
+
key = $key
|
|
252
|
+
seconds = $input.window_seconds
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
precondition ($count <= $input.max_requests) {
|
|
258
|
+
error_type = "standard"
|
|
259
|
+
error = "Rate limit exceeded"
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
response = { remaining: $input.max_requests - $count }
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### Response Caching
|
|
268
|
+
|
|
269
|
+
```xs
|
|
270
|
+
middleware "cache_response" {
|
|
271
|
+
description = "Caches responses in Redis"
|
|
272
|
+
exception_policy = "silent"
|
|
273
|
+
|
|
274
|
+
input {
|
|
275
|
+
text cache_key
|
|
276
|
+
int ttl_seconds?=300
|
|
277
|
+
json response_data
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
stack {
|
|
281
|
+
redis.set {
|
|
282
|
+
key = $input.cache_key
|
|
283
|
+
value = $input.response_data|json_encode
|
|
284
|
+
expire = $input.ttl_seconds
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
response = null
|
|
289
|
+
}
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
---
|
|
293
|
+
|
|
294
|
+
## Applying Middleware
|
|
295
|
+
|
|
296
|
+
Middleware is configured at the branch level. See `xanoscript_docs({ topic: "branch" })` for configuration details.
|
|
297
|
+
|
|
298
|
+
```xs
|
|
299
|
+
branch "production" {
|
|
300
|
+
middleware = {
|
|
301
|
+
query: {
|
|
302
|
+
pre: ["validate_token", "rate_limit"],
|
|
303
|
+
post: ["audit_log", "cache_response"]
|
|
304
|
+
},
|
|
305
|
+
function: {
|
|
306
|
+
pre: ["validate_token"],
|
|
307
|
+
post: ["audit_log"]
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
---
|
|
314
|
+
|
|
315
|
+
## Best Practices
|
|
316
|
+
|
|
317
|
+
1. **Keep middleware focused** - Each middleware should do one thing well
|
|
318
|
+
2. **Use appropriate exception policies** - Critical for security, silent for optional enrichment
|
|
319
|
+
3. **Consider performance** - Middleware runs on every request
|
|
320
|
+
4. **Log failures** - Even silent failures should be logged for debugging
|
|
321
|
+
5. **Test independently** - Middleware should be testable in isolation
|
|
@@ -42,11 +42,123 @@ api.realtime_event {
|
|
|
42
42
|
|
|
43
43
|
---
|
|
44
44
|
|
|
45
|
+
## Realtime Channel Configuration
|
|
46
|
+
|
|
47
|
+
Define channel settings at the workspace level using `realtime_channel`.
|
|
48
|
+
|
|
49
|
+
```xs
|
|
50
|
+
realtime_channel "<channel_pattern>" {
|
|
51
|
+
description = "Channel description"
|
|
52
|
+
active = true
|
|
53
|
+
|
|
54
|
+
public_messaging = {
|
|
55
|
+
active: true,
|
|
56
|
+
auth: false
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
private_messaging = {
|
|
60
|
+
active: true,
|
|
61
|
+
auth: true
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
settings = {
|
|
65
|
+
anonymous_clients: false,
|
|
66
|
+
nested_channels: true,
|
|
67
|
+
message_history: 100,
|
|
68
|
+
auth_channel: true,
|
|
69
|
+
presence: true
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Channel Configuration Options
|
|
75
|
+
|
|
76
|
+
| Attribute | Type | Description |
|
|
77
|
+
|-----------|------|-------------|
|
|
78
|
+
| `description` | text | Human-readable channel description |
|
|
79
|
+
| `active` | boolean | Enable/disable the channel |
|
|
80
|
+
|
|
81
|
+
### Messaging Options
|
|
82
|
+
|
|
83
|
+
| Setting | Type | Description |
|
|
84
|
+
|---------|------|-------------|
|
|
85
|
+
| `public_messaging.active` | boolean | Allow public messages |
|
|
86
|
+
| `public_messaging.auth` | boolean | Require authentication for public messages |
|
|
87
|
+
| `private_messaging.active` | boolean | Allow private messages |
|
|
88
|
+
| `private_messaging.auth` | boolean | Require authentication for private messages |
|
|
89
|
+
|
|
90
|
+
### Settings Options
|
|
91
|
+
|
|
92
|
+
| Setting | Type | Values | Description |
|
|
93
|
+
|---------|------|--------|-------------|
|
|
94
|
+
| `anonymous_clients` | boolean | true/false | Allow unauthenticated clients |
|
|
95
|
+
| `nested_channels` | boolean | true/false | Allow sub-channel patterns |
|
|
96
|
+
| `message_history` | number | 0, 25, 50, 100, 250, 1000 | Messages to retain |
|
|
97
|
+
| `auth_channel` | boolean | true/false | Require channel-level auth |
|
|
98
|
+
| `presence` | boolean | true/false | Track client presence |
|
|
99
|
+
|
|
100
|
+
### Example Configurations
|
|
101
|
+
|
|
102
|
+
```xs
|
|
103
|
+
// Chat room channel with presence
|
|
104
|
+
realtime_channel "room:*" {
|
|
105
|
+
description = "Chat room channels"
|
|
106
|
+
active = true
|
|
107
|
+
|
|
108
|
+
public_messaging = { active: true, auth: true }
|
|
109
|
+
private_messaging = { active: true, auth: true }
|
|
110
|
+
|
|
111
|
+
settings = {
|
|
112
|
+
anonymous_clients: false,
|
|
113
|
+
nested_channels: false,
|
|
114
|
+
message_history: 100,
|
|
115
|
+
auth_channel: true,
|
|
116
|
+
presence: true
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Global announcements (read-only for clients)
|
|
121
|
+
realtime_channel "announcements" {
|
|
122
|
+
description = "System-wide announcements"
|
|
123
|
+
active = true
|
|
124
|
+
|
|
125
|
+
public_messaging = { active: true, auth: false }
|
|
126
|
+
private_messaging = { active: false, auth: false }
|
|
127
|
+
|
|
128
|
+
settings = {
|
|
129
|
+
anonymous_clients: true,
|
|
130
|
+
nested_channels: false,
|
|
131
|
+
message_history: 25,
|
|
132
|
+
auth_channel: false,
|
|
133
|
+
presence: false
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// User-specific notifications
|
|
138
|
+
realtime_channel "user:*" {
|
|
139
|
+
description = "User notification channels"
|
|
140
|
+
active = true
|
|
141
|
+
|
|
142
|
+
public_messaging = { active: false, auth: false }
|
|
143
|
+
private_messaging = { active: true, auth: true }
|
|
144
|
+
|
|
145
|
+
settings = {
|
|
146
|
+
anonymous_clients: false,
|
|
147
|
+
nested_channels: false,
|
|
148
|
+
message_history: 50,
|
|
149
|
+
auth_channel: true,
|
|
150
|
+
presence: false
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
45
157
|
## Channel Patterns
|
|
46
158
|
|
|
47
159
|
### Public Channels
|
|
48
160
|
|
|
49
|
-
|
|
161
|
+
Accessible to all authenticated clients. When you send to a public channel, all clients currently subscribed to that channel receive the message.
|
|
50
162
|
|
|
51
163
|
```xs
|
|
52
164
|
// Global announcements
|
|
@@ -62,7 +62,7 @@ tool "get_user_by_email" {
|
|
|
62
62
|
|
|
63
63
|
## Input Block
|
|
64
64
|
|
|
65
|
-
For complete type reference, use `xanoscript_docs({
|
|
65
|
+
For complete type reference, use `xanoscript_docs({ topic: "types" })`. For tools, input `description` fields are sent to the AI, so write them clearly:
|
|
66
66
|
|
|
67
67
|
```xs
|
|
68
68
|
input {
|
|
@@ -62,7 +62,13 @@ input {
|
|
|
62
62
|
|
|
63
63
|
### Empty Input Blocks
|
|
64
64
|
|
|
65
|
-
**
|
|
65
|
+
**SYNTAX REQUIREMENT:** When an input block has no parameters, the braces MUST be on separate lines.
|
|
66
|
+
|
|
67
|
+
**Why:** The XanoScript parser requires whitespace between braces to distinguish empty input blocks from inline objects.
|
|
68
|
+
|
|
69
|
+
**Impact:** Using `input {}` on a single line will cause:
|
|
70
|
+
- Syntax error during compilation
|
|
71
|
+
- Function/API/tool will fail to deploy
|
|
66
72
|
|
|
67
73
|
```xs
|
|
68
74
|
// CORRECT - braces on separate lines
|
|
@@ -109,6 +115,21 @@ email contact filters=trim|lower {
|
|
|
109
115
|
password secret filters=min:8 // Minimum 8 characters
|
|
110
116
|
```
|
|
111
117
|
|
|
118
|
+
#### Password Complexity Filters
|
|
119
|
+
| Filter | Description | Example |
|
|
120
|
+
|--------|-------------|---------|
|
|
121
|
+
| `min:<n>` | Minimum total length | `password pwd filters=min:8` |
|
|
122
|
+
| `minAlpha:<n>` | Minimum letters (a-zA-Z) | `password pwd filters=minAlpha:2` |
|
|
123
|
+
| `minLowerAlpha:<n>` | Minimum lowercase letters | `password pwd filters=minLowerAlpha:1` |
|
|
124
|
+
| `minUpperAlpha:<n>` | Minimum uppercase letters | `password pwd filters=minUpperAlpha:1` |
|
|
125
|
+
| `minDigit:<n>` | Minimum digits (0-9) | `password pwd filters=minDigit:1` |
|
|
126
|
+
| `minSymbol:<n>` | Minimum special characters | `password pwd filters=minSymbol:1` |
|
|
127
|
+
|
|
128
|
+
```xs
|
|
129
|
+
// Strong password: 8+ chars, 1 upper, 1 lower, 1 digit, 1 symbol
|
|
130
|
+
password strong_pwd filters=min:8|minUpperAlpha:1|minLowerAlpha:1|minDigit:1|minSymbol:1
|
|
131
|
+
```
|
|
132
|
+
|
|
112
133
|
### timestamp / date
|
|
113
134
|
```xs
|
|
114
135
|
timestamp created_at?=now // Defaults to current time
|
|
@@ -199,10 +220,8 @@ Filters validate and transform input values. Chain with `|`.
|
|
|
199
220
|
| `ok:<chars>` | Allow only specified characters | `text hex filters=ok:0123456789abcdef` |
|
|
200
221
|
| `prevent:<str>` | Block specific substrings | `text name filters=prevent:admin` |
|
|
201
222
|
| `startsWith:<prefix>` | Require prefix | `text sku filters=startsWith:SKU-` |
|
|
202
|
-
| `endsWith:<suffix>` | Require suffix | `text file filters=endsWith:.pdf` |
|
|
203
223
|
| `alphaOk` | Allow only letters (a-zA-Z) | `text name filters=alphaOk` |
|
|
204
224
|
| `digitOk` | Allow only digits (0-9) | `text code filters=digitOk` |
|
|
205
|
-
| `alphaNumOk` | Allow letters and digits | `text username filters=alphaNumOk` |
|
|
206
225
|
| `pattern:<regex>` | Match regex pattern | `text phone filters=pattern:^\+?[0-9]+$` |
|
|
207
226
|
|
|
208
227
|
### Numeric Filters
|
|
@@ -210,14 +229,12 @@ Filters validate and transform input values. Chain with `|`.
|
|
|
210
229
|
|--------|-------------|---------|
|
|
211
230
|
| `min:<n>` | Minimum value | `int age filters=min:0` |
|
|
212
231
|
| `max:<n>` | Maximum value | `int age filters=max:150` |
|
|
213
|
-
| `between:<a>:<b>` | Value between a and b | `int score filters=between:0:100` |
|
|
214
232
|
|
|
215
233
|
### Array Filters
|
|
216
234
|
| Filter | Description | Example |
|
|
217
235
|
|--------|-------------|---------|
|
|
218
236
|
| `min:<n>` | Minimum array length | `text[] tags filters=min:1` |
|
|
219
237
|
| `max:<n>` | Maximum array length | `text[] tags filters=max:10` |
|
|
220
|
-
| `unique` | Remove duplicates | `int[] ids filters=unique` |
|
|
221
238
|
|
|
222
239
|
### Character Set Filters
|
|
223
240
|
|
|
@@ -255,11 +272,11 @@ input {
|
|
|
255
272
|
### Combined Examples
|
|
256
273
|
```xs
|
|
257
274
|
input {
|
|
258
|
-
text username filters=trim|lower|min:3|max:20|
|
|
275
|
+
text username filters=trim|lower|min:3|max:20|ok:abcdefghijklmnopqrstuvwxyz0123456789_
|
|
259
276
|
email contact filters=trim|lower
|
|
260
277
|
int age filters=min:0|max:150
|
|
261
278
|
text hex_code filters=ok:abcdef0123456789|min:6|max:6
|
|
262
|
-
text[] tags filters=trim|lower|max:50
|
|
279
|
+
text[] tags filters=trim|lower|max:50
|
|
263
280
|
text phone filters=trim|pattern:^\+?[0-9\s-]+$
|
|
264
281
|
int quantity filters=min:1|max:100
|
|
265
282
|
}
|
|
@@ -326,7 +343,7 @@ input {
|
|
|
326
343
|
|
|
327
344
|
## Validation with Preconditions
|
|
328
345
|
|
|
329
|
-
For complex validation beyond filters, use preconditions. For complete error handling reference, use `xanoscript_docs({
|
|
346
|
+
For complex validation beyond filters, use preconditions. For complete error handling reference, use `xanoscript_docs({ topic: "syntax" })`.
|
|
330
347
|
|
|
331
348
|
```xs
|
|
332
349
|
precondition ($input.start_date < $input.end_date) {
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
---
|
|
2
|
+
applyTo: "workspace.xs"
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Workspace Configuration
|
|
6
|
+
|
|
7
|
+
Configure workspace-level settings including environment variables, preferences, and realtime configuration.
|
|
8
|
+
|
|
9
|
+
## Quick Reference
|
|
10
|
+
|
|
11
|
+
```xs
|
|
12
|
+
workspace "<name>" {
|
|
13
|
+
description = "Workspace description"
|
|
14
|
+
env = { ... }
|
|
15
|
+
acceptance = { ... }
|
|
16
|
+
preferences = { ... }
|
|
17
|
+
realtime = { ... }
|
|
18
|
+
}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Attributes
|
|
22
|
+
| Attribute | Type | Required | Description |
|
|
23
|
+
|-----------|------|----------|-------------|
|
|
24
|
+
| `description` | text | No | Human-readable workspace description |
|
|
25
|
+
| `env` | object | No | Environment variable definitions |
|
|
26
|
+
| `acceptance` | object | No | Terms and acceptance settings |
|
|
27
|
+
| `preferences` | object | No | Workspace behavior preferences |
|
|
28
|
+
| `realtime` | object | No | Realtime channel configuration |
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Basic Structure
|
|
33
|
+
|
|
34
|
+
```xs
|
|
35
|
+
workspace "my_project" {
|
|
36
|
+
description = "My XanoScript project workspace"
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Environment Variables
|
|
43
|
+
|
|
44
|
+
Define environment variables accessible via `$env.<name>` in your code.
|
|
45
|
+
|
|
46
|
+
```xs
|
|
47
|
+
workspace "my_project" {
|
|
48
|
+
env = {
|
|
49
|
+
API_KEY: "your-api-key",
|
|
50
|
+
DATABASE_URL: "postgresql://...",
|
|
51
|
+
REDIS_URL: "redis://...",
|
|
52
|
+
ENVIRONMENT: "production"
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Accessing Environment Variables
|
|
58
|
+
|
|
59
|
+
```xs
|
|
60
|
+
// In any function, query, or task
|
|
61
|
+
stack {
|
|
62
|
+
var $key { value = $env.API_KEY }
|
|
63
|
+
|
|
64
|
+
api.call "external_api" {
|
|
65
|
+
url = $env.DATABASE_URL ~ "/endpoint"
|
|
66
|
+
headers = {
|
|
67
|
+
"Authorization": "Bearer " ~ $env.API_KEY
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Acceptance Settings
|
|
76
|
+
|
|
77
|
+
Configure terms and acceptance requirements.
|
|
78
|
+
|
|
79
|
+
```xs
|
|
80
|
+
workspace "my_project" {
|
|
81
|
+
acceptance = {
|
|
82
|
+
ai_terms: true
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Acceptance Options
|
|
88
|
+
|
|
89
|
+
| Option | Type | Description |
|
|
90
|
+
|--------|------|-------------|
|
|
91
|
+
| `ai_terms` | boolean | Accept AI feature terms of service |
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Preferences
|
|
96
|
+
|
|
97
|
+
Configure workspace behavior and features.
|
|
98
|
+
|
|
99
|
+
```xs
|
|
100
|
+
workspace "my_project" {
|
|
101
|
+
preferences = {
|
|
102
|
+
internal_docs: true,
|
|
103
|
+
sql_columns: true,
|
|
104
|
+
sql_names: true,
|
|
105
|
+
track_performance: true
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Preference Options
|
|
111
|
+
|
|
112
|
+
| Option | Type | Default | Description |
|
|
113
|
+
|--------|------|---------|-------------|
|
|
114
|
+
| `internal_docs` | boolean | false | Enable internal documentation generation |
|
|
115
|
+
| `sql_columns` | boolean | false | Include SQL column names in output |
|
|
116
|
+
| `sql_names` | boolean | false | Include SQL table names in output |
|
|
117
|
+
| `track_performance` | boolean | false | Enable performance tracking and metrics |
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Realtime Configuration
|
|
122
|
+
|
|
123
|
+
Configure realtime channel settings.
|
|
124
|
+
|
|
125
|
+
```xs
|
|
126
|
+
workspace "my_project" {
|
|
127
|
+
realtime = {
|
|
128
|
+
canonical: "my-project"
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Realtime Options
|
|
134
|
+
|
|
135
|
+
| Option | Type | Description |
|
|
136
|
+
|--------|------|-------------|
|
|
137
|
+
| `canonical` | text | Base URL path for realtime channels |
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Complete Example
|
|
142
|
+
|
|
143
|
+
```xs
|
|
144
|
+
workspace "ecommerce_platform" {
|
|
145
|
+
description = "E-commerce backend workspace"
|
|
146
|
+
|
|
147
|
+
env = {
|
|
148
|
+
STRIPE_KEY: "sk_live_...",
|
|
149
|
+
SENDGRID_KEY: "SG...",
|
|
150
|
+
AWS_REGION: "us-east-1",
|
|
151
|
+
S3_BUCKET: "ecommerce-assets",
|
|
152
|
+
REDIS_URL: "redis://cache.example.com:6379"
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
acceptance = {
|
|
156
|
+
ai_terms: true
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
preferences = {
|
|
160
|
+
internal_docs: true,
|
|
161
|
+
track_performance: true
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
realtime = {
|
|
165
|
+
canonical: "ecommerce"
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## File Location
|
|
173
|
+
|
|
174
|
+
Workspace configuration is stored in `workspace.xs` at the root of your project.
|
|
175
|
+
|
|
176
|
+
```
|
|
177
|
+
project/
|
|
178
|
+
├── workspace.xs // Workspace configuration
|
|
179
|
+
├── branch.xs // Branch configuration
|
|
180
|
+
├── tables/
|
|
181
|
+
├── functions/
|
|
182
|
+
└── apis/
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## Built-in Environment Variables
|
|
188
|
+
|
|
189
|
+
These variables are automatically available without configuration:
|
|
190
|
+
|
|
191
|
+
| Variable | Description |
|
|
192
|
+
|----------|-------------|
|
|
193
|
+
| `$env.$remote_ip` | Client IP address |
|
|
194
|
+
| `$env.$http_headers` | Request headers array |
|
|
195
|
+
| `$env.$request_uri` | Request URI |
|
|
196
|
+
| `$env.$request_method` | HTTP method (GET, POST, etc.) |
|
|
197
|
+
| `$env.$request_querystring` | Query string |
|
|
198
|
+
| `$env.$datasource` | Current datasource |
|
|
199
|
+
| `$env.$branch` | Current branch name |
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## Best Practices
|
|
204
|
+
|
|
205
|
+
1. **Never commit secrets** - Use environment variables for API keys and credentials
|
|
206
|
+
2. **Use descriptive names** - Environment variable names should be self-documenting
|
|
207
|
+
3. **Enable performance tracking** - Helps identify bottlenecks in production
|
|
208
|
+
4. **Set meaningful canonical paths** - Makes realtime channel URLs predictable
|
|
209
|
+
5. **Document your workspace** - Use the description field for team reference
|