@xano/developer-mcp 1.0.27 → 1.0.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/api_docs/format.d.ts +5 -0
- package/dist/api_docs/format.js +171 -0
- package/dist/api_docs/index.d.ts +52 -0
- package/dist/api_docs/index.js +111 -0
- package/dist/api_docs/topics/agent.d.ts +2 -0
- package/dist/api_docs/topics/agent.js +142 -0
- package/dist/api_docs/topics/api.d.ts +2 -0
- package/dist/api_docs/topics/api.js +176 -0
- package/dist/api_docs/topics/apigroup.d.ts +2 -0
- package/dist/api_docs/topics/apigroup.js +124 -0
- package/dist/api_docs/topics/authentication.d.ts +2 -0
- package/dist/api_docs/topics/authentication.js +61 -0
- package/dist/api_docs/topics/branch.d.ts +2 -0
- package/dist/api_docs/topics/branch.js +73 -0
- package/dist/api_docs/topics/file.d.ts +2 -0
- package/dist/api_docs/topics/file.js +70 -0
- package/dist/api_docs/topics/function.d.ts +2 -0
- package/dist/api_docs/topics/function.js +164 -0
- package/dist/api_docs/topics/history.d.ts +2 -0
- package/dist/api_docs/topics/history.js +149 -0
- package/dist/api_docs/topics/mcp_server.d.ts +2 -0
- package/dist/api_docs/topics/mcp_server.js +139 -0
- package/dist/api_docs/topics/middleware.d.ts +2 -0
- package/dist/api_docs/topics/middleware.js +156 -0
- package/dist/api_docs/topics/realtime.d.ts +2 -0
- package/dist/api_docs/topics/realtime.js +112 -0
- package/dist/api_docs/topics/start.d.ts +2 -0
- package/dist/api_docs/topics/start.js +107 -0
- package/dist/api_docs/topics/table.d.ts +2 -0
- package/dist/api_docs/topics/table.js +195 -0
- package/dist/api_docs/topics/task.d.ts +2 -0
- package/dist/api_docs/topics/task.js +165 -0
- package/dist/api_docs/topics/tool.d.ts +2 -0
- package/dist/api_docs/topics/tool.js +150 -0
- package/dist/api_docs/topics/workflows.d.ts +2 -0
- package/dist/api_docs/topics/workflows.js +131 -0
- package/dist/api_docs/topics/workspace.d.ts +2 -0
- package/dist/api_docs/topics/workspace.js +153 -0
- package/dist/api_docs/types.d.ts +79 -0
- package/dist/api_docs/types.js +4 -0
- package/dist/meta_api_docs/topics/branch.js +154 -18
- package/dist/meta_api_docs/topics/workspace.js +45 -2
- package/dist/templates/init-workspace.d.ts +10 -0
- package/dist/templates/init-workspace.js +278 -0
- package/dist/templates/xanoscript-index.d.ts +11 -0
- package/dist/templates/xanoscript-index.js +72 -0
- package/dist/xanoscript_docs/README.md +3 -13
- package/dist/xanoscript_docs/ephemeral.md +330 -0
- package/dist/xanoscript_docs/functions.md +0 -21
- package/dist/xanoscript_docs/integrations.md +0 -10
- package/dist/xanoscript_docs/performance.md +1 -10
- package/dist/xanoscript_docs/realtime.md +1 -48
- package/dist/xanoscript_docs/security.md +2 -0
- package/dist/xanoscript_docs/tools.md +2 -21
- package/dist/xanoscript_docs/triggers.md +2 -27
- package/dist/xanoscript_docs_auto/README.md +119 -0
- package/dist/xanoscript_docs_auto/agents.md +446 -0
- package/dist/xanoscript_docs_auto/apis.md +517 -0
- package/dist/xanoscript_docs_auto/control-flow.md +543 -0
- package/dist/xanoscript_docs_auto/database.md +551 -0
- package/dist/xanoscript_docs_auto/debugging.md +527 -0
- package/dist/xanoscript_docs_auto/filters.md +464 -0
- package/dist/xanoscript_docs_auto/functions.md +431 -0
- package/dist/xanoscript_docs_auto/integrations.md +657 -0
- package/dist/xanoscript_docs_auto/mcp-servers.md +408 -0
- package/dist/xanoscript_docs_auto/operators.md +368 -0
- package/dist/xanoscript_docs_auto/syntax.md +287 -0
- package/dist/xanoscript_docs_auto/tables.md +447 -0
- package/dist/xanoscript_docs_auto/tasks.md +479 -0
- package/dist/xanoscript_docs_auto/testing.md +574 -0
- package/dist/xanoscript_docs_auto/tools.md +485 -0
- package/dist/xanoscript_docs_auto/triggers.md +595 -0
- package/dist/xanoscript_docs_auto/types.md +323 -0
- package/dist/xanoscript_docs_auto/variables.md +462 -0
- package/dist/xanoscript_docs_auto/version.json +5 -0
- package/package.json +1 -1
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template for init_workspace tool documentation
|
|
3
|
+
* Edit this file to update the workspace initialization guide
|
|
4
|
+
*/
|
|
5
|
+
export function generateInitWorkspaceTemplate(objectTypes) {
|
|
6
|
+
const objectTypesTable = objectTypes
|
|
7
|
+
.map(({ type, path, endpoint }) => `| \`${type}\` | \`${path}/\` | \`${endpoint}\` |`)
|
|
8
|
+
.join("\n");
|
|
9
|
+
return `# Xano Workspace Initialization Guide
|
|
10
|
+
|
|
11
|
+
This guide explains how to set up a local development workspace that syncs with the Xano Headless API.
|
|
12
|
+
|
|
13
|
+
## Directory Structure
|
|
14
|
+
|
|
15
|
+
Initialize your workspace with these directories:
|
|
16
|
+
|
|
17
|
+
\`\`\`
|
|
18
|
+
your-project/
|
|
19
|
+
├── .xano/
|
|
20
|
+
│ └── registry.json # Tracks all objects and their sync state
|
|
21
|
+
├── functions/ # Custom reusable functions
|
|
22
|
+
│ ├── calculate_total.xs
|
|
23
|
+
│ └── validate_email.xs
|
|
24
|
+
├── tables/ # Database table schemas
|
|
25
|
+
│ ├── user.xs
|
|
26
|
+
│ └── order.xs
|
|
27
|
+
├── tasks/ # Scheduled background tasks
|
|
28
|
+
│ └── cleanup_sessions.xs
|
|
29
|
+
├── apis/ # API groups and endpoints
|
|
30
|
+
│ └── auth/ # API group directory
|
|
31
|
+
│ ├── api_group.xs # Group definition
|
|
32
|
+
│ ├── POST_login.xs # Endpoint: POST /auth/login
|
|
33
|
+
│ └── GET_me.xs # Endpoint: GET /auth/me
|
|
34
|
+
├── tools/ # AI-callable tools
|
|
35
|
+
├── agents/ # AI agents
|
|
36
|
+
├── middlewares/ # Request/response middleware
|
|
37
|
+
├── addons/ # Query addons
|
|
38
|
+
├── mcp_servers/ # MCP servers
|
|
39
|
+
└── realtime/ # Realtime channels
|
|
40
|
+
\`\`\`
|
|
41
|
+
|
|
42
|
+
## Object Types
|
|
43
|
+
|
|
44
|
+
| Type | Directory | API Endpoint |
|
|
45
|
+
|------|-----------|--------------|
|
|
46
|
+
${objectTypesTable}
|
|
47
|
+
|
|
48
|
+
## File Naming Convention
|
|
49
|
+
|
|
50
|
+
Files should follow snake_case naming with the \`.xs\` extension:
|
|
51
|
+
- \`{name}.xs\` - Basic format (e.g., \`calculate_total.xs\`)
|
|
52
|
+
- \`{id}_{name}.xs\` - With ID prefix for disambiguation (e.g., \`42_calculate_total.xs\`)
|
|
53
|
+
- API endpoints: \`{VERB}_{path}.xs\` (e.g., \`POST_login.xs\`, \`GET_users_id.xs\`)
|
|
54
|
+
|
|
55
|
+
## Registry Format
|
|
56
|
+
|
|
57
|
+
The \`.xano/registry.json\` file tracks the sync state between local files and the Xano API:
|
|
58
|
+
|
|
59
|
+
\`\`\`json
|
|
60
|
+
{
|
|
61
|
+
"workspace_id": 12345,
|
|
62
|
+
"workspace_name": "My Project",
|
|
63
|
+
"branch": "",
|
|
64
|
+
"base_url": "https://your-instance.xano.io/api:headless",
|
|
65
|
+
"created_at": "2025-01-15T10:30:00Z",
|
|
66
|
+
"updated_at": "2025-01-15T10:30:00Z",
|
|
67
|
+
"objects": [
|
|
68
|
+
{
|
|
69
|
+
"id": 1,
|
|
70
|
+
"type": "function",
|
|
71
|
+
"name": "calculate_total",
|
|
72
|
+
"path": "functions/calculate_total.xs",
|
|
73
|
+
"sha256": "abc123...",
|
|
74
|
+
"status": "unchanged",
|
|
75
|
+
"original": "ZnVuY3Rpb24gY2FsY3VsYXRlX3RvdGFsIHsgLi4uIH0=",
|
|
76
|
+
"updated_at": "2025-01-15T10:30:00Z"
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"id": 0,
|
|
80
|
+
"type": "function",
|
|
81
|
+
"name": "new_function",
|
|
82
|
+
"path": "functions/new_function.xs",
|
|
83
|
+
"status": "new"
|
|
84
|
+
}
|
|
85
|
+
]
|
|
86
|
+
}
|
|
87
|
+
\`\`\`
|
|
88
|
+
|
|
89
|
+
### Registry Record Fields
|
|
90
|
+
|
|
91
|
+
| Field | Description |
|
|
92
|
+
|-------|-------------|
|
|
93
|
+
| \`id\` | Xano object ID (0 = new, not yet synced) |
|
|
94
|
+
| \`type\` | Object type (function, table, task, etc.) |
|
|
95
|
+
| \`name\` | Object name extracted from XanoScript |
|
|
96
|
+
| \`path\` | Relative file path from workspace root |
|
|
97
|
+
| \`sha256\` | SHA256 hash of file content for change detection |
|
|
98
|
+
| \`status\` | Sync status: "new", "unchanged", "changed", "deleted" |
|
|
99
|
+
| \`original\` | Base64-encoded original content (for conflict detection) |
|
|
100
|
+
| \`updated_at\` | Last sync timestamp |
|
|
101
|
+
|
|
102
|
+
### Status Values
|
|
103
|
+
|
|
104
|
+
| Status | Description |
|
|
105
|
+
|--------|-------------|
|
|
106
|
+
| \`new\` | Created locally, not yet pushed to Xano |
|
|
107
|
+
| \`unchanged\` | In sync with remote |
|
|
108
|
+
| \`changed\` | Modified locally since last sync |
|
|
109
|
+
| \`deleted\` | Marked for deletion (file removed locally) |
|
|
110
|
+
|
|
111
|
+
## Fetching Objects from the API
|
|
112
|
+
|
|
113
|
+
Use the Headless API to fetch objects.
|
|
114
|
+
|
|
115
|
+
### List Objects
|
|
116
|
+
|
|
117
|
+
\`\`\`
|
|
118
|
+
GET /workspace/{workspace_id}/{type}
|
|
119
|
+
Headers:
|
|
120
|
+
Authorization: Bearer {token}
|
|
121
|
+
|
|
122
|
+
Query Parameters:
|
|
123
|
+
- branch: Branch label (empty = live branch)
|
|
124
|
+
- page: Page number (default: 1)
|
|
125
|
+
- per_page: Items per page (default: 50, max: 10000)
|
|
126
|
+
- search: Text search filter
|
|
127
|
+
- sort: Sort field (created_at, updated_at, name)
|
|
128
|
+
- order: asc or desc
|
|
129
|
+
\`\`\`
|
|
130
|
+
|
|
131
|
+
### Get Single Object with XanoScript
|
|
132
|
+
|
|
133
|
+
\`\`\`
|
|
134
|
+
GET /workspace/{workspace_id}/{type}/{id}
|
|
135
|
+
Headers:
|
|
136
|
+
Authorization: Bearer {token}
|
|
137
|
+
|
|
138
|
+
Query Parameters:
|
|
139
|
+
- branch: Branch label
|
|
140
|
+
\`\`\`
|
|
141
|
+
|
|
142
|
+
The response includes the \`xanoscript\` field with the code content:
|
|
143
|
+
\`\`\`json
|
|
144
|
+
{
|
|
145
|
+
"id": 1,
|
|
146
|
+
"name": "calculate_total",
|
|
147
|
+
"xanoscript": {
|
|
148
|
+
"status": "ok",
|
|
149
|
+
"value": "function calculate_total { ... }"
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
\`\`\`
|
|
153
|
+
|
|
154
|
+
### API Endpoints (Nested Under API Groups)
|
|
155
|
+
|
|
156
|
+
**Important:** API endpoints are nested resources under API groups. You must first fetch API groups to obtain their IDs, then use those IDs to fetch the endpoints within each group.
|
|
157
|
+
|
|
158
|
+
\`\`\`
|
|
159
|
+
# 1. First, list API groups
|
|
160
|
+
GET /workspace/{workspace_id}/apigroup
|
|
161
|
+
|
|
162
|
+
# 2. Then, list endpoints for each group using the apigroup_id
|
|
163
|
+
GET /workspace/{workspace_id}/apigroup/{apigroup_id}/api
|
|
164
|
+
|
|
165
|
+
# 3. Get a single endpoint
|
|
166
|
+
GET /workspace/{workspace_id}/apigroup/{apigroup_id}/api/{api_id}
|
|
167
|
+
\`\`\`
|
|
168
|
+
|
|
169
|
+
This hierarchical structure is reflected in the local directory layout:
|
|
170
|
+
\`\`\`
|
|
171
|
+
apis/
|
|
172
|
+
└── auth/ # API group (apigroup_id required)
|
|
173
|
+
├── api_group.xs # Group definition
|
|
174
|
+
├── POST_login.xs # Endpoint within this group
|
|
175
|
+
└── GET_me.xs # Another endpoint
|
|
176
|
+
\`\`\`
|
|
177
|
+
|
|
178
|
+
API groups contain endpoints that share common configuration.
|
|
179
|
+
|
|
180
|
+
## Pull Workflow
|
|
181
|
+
|
|
182
|
+
1. **Fetch object list** from API (paginated)
|
|
183
|
+
2. **For each object**, get the full definition including XanoScript
|
|
184
|
+
3. **Generate file path** based on type and name
|
|
185
|
+
4. **Write file** to the appropriate directory
|
|
186
|
+
5. **Update registry** with object metadata and SHA256 hash
|
|
187
|
+
|
|
188
|
+
### Example Pull Request Sequence
|
|
189
|
+
|
|
190
|
+
\`\`\`javascript
|
|
191
|
+
// 1. List all functions
|
|
192
|
+
const response = await fetch(
|
|
193
|
+
\`\${baseUrl}/workspace/\${workspaceId}/function?branch=\${branch}&per_page=100\`,
|
|
194
|
+
{ headers: { Authorization: \`Bearer \${token}\` } }
|
|
195
|
+
);
|
|
196
|
+
const { items, nextPage } = await response.json();
|
|
197
|
+
|
|
198
|
+
// 2. For each function, save to file
|
|
199
|
+
for (const func of items) {
|
|
200
|
+
const xanoscript = func.xanoscript?.value || '';
|
|
201
|
+
const fileName = \`\${snakeCase(func.name)}.xs\`;
|
|
202
|
+
const filePath = \`functions/\${fileName}\`;
|
|
203
|
+
|
|
204
|
+
// Write file
|
|
205
|
+
await writeFile(filePath, xanoscript);
|
|
206
|
+
|
|
207
|
+
// Add to registry
|
|
208
|
+
registry.objects.push({
|
|
209
|
+
id: func.id,
|
|
210
|
+
type: 'function',
|
|
211
|
+
name: func.name,
|
|
212
|
+
path: filePath,
|
|
213
|
+
sha256: sha256(xanoscript),
|
|
214
|
+
status: 'unchanged',
|
|
215
|
+
original: btoa(xanoscript),
|
|
216
|
+
updated_at: func.updated_at
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
\`\`\`
|
|
220
|
+
|
|
221
|
+
## Push Workflow
|
|
222
|
+
|
|
223
|
+
1. **Read registry** to find changed/new objects
|
|
224
|
+
2. **For each changed file**, read content and detect changes
|
|
225
|
+
3. **Create or update** via API with XanoScript content
|
|
226
|
+
4. **Update registry** with new IDs and hashes
|
|
227
|
+
|
|
228
|
+
### Example Push Request
|
|
229
|
+
|
|
230
|
+
\`\`\`javascript
|
|
231
|
+
// Create new function
|
|
232
|
+
const response = await fetch(
|
|
233
|
+
\`\${baseUrl}/workspace/\${workspaceId}/function?branch=\${branch}\`,
|
|
234
|
+
{
|
|
235
|
+
method: 'POST',
|
|
236
|
+
headers: {
|
|
237
|
+
'Authorization': \`Bearer \${token}\`,
|
|
238
|
+
'Content-Type': 'text/x-xanoscript'
|
|
239
|
+
},
|
|
240
|
+
body: xanoscriptContent
|
|
241
|
+
}
|
|
242
|
+
);
|
|
243
|
+
|
|
244
|
+
// Update existing function
|
|
245
|
+
const response = await fetch(
|
|
246
|
+
\`\${baseUrl}/workspace/\${workspaceId}/function/\${functionId}?publish=true\`,
|
|
247
|
+
{
|
|
248
|
+
method: 'PUT',
|
|
249
|
+
headers: {
|
|
250
|
+
'Authorization': \`Bearer \${token}\`,
|
|
251
|
+
'Content-Type': 'text/x-xanoscript'
|
|
252
|
+
},
|
|
253
|
+
body: xanoscriptContent
|
|
254
|
+
}
|
|
255
|
+
);
|
|
256
|
+
\`\`\`
|
|
257
|
+
|
|
258
|
+
## XanoScript Documentation References
|
|
259
|
+
|
|
260
|
+
For writing XanoScript code, use:
|
|
261
|
+
|
|
262
|
+
- \`xanoscript_docs()\` - Full documentation index
|
|
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
|
+
|
|
268
|
+
## Validating XanoScript
|
|
269
|
+
|
|
270
|
+
Before pushing changes, validate the XanoScript syntax:
|
|
271
|
+
|
|
272
|
+
\`\`\`
|
|
273
|
+
validate_xanoscript({ code: "function foo { ... }" })
|
|
274
|
+
\`\`\`
|
|
275
|
+
|
|
276
|
+
This will check for syntax errors and return line/column positions for any issues.
|
|
277
|
+
`;
|
|
278
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template for xanoscript_docs index documentation
|
|
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.
|
|
7
|
+
*/
|
|
8
|
+
export interface XanoscriptIndexParams {
|
|
9
|
+
version: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function generateXanoscriptIndexTemplate(params: XanoscriptIndexParams): string;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template for xanoscript_docs index documentation
|
|
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.
|
|
7
|
+
*/
|
|
8
|
+
export function generateXanoscriptIndexTemplate(params) {
|
|
9
|
+
const { version } = params;
|
|
10
|
+
return `# XanoScript Documentation Index
|
|
11
|
+
Version: ${version}
|
|
12
|
+
|
|
13
|
+
Use \`xanoscript_docs({ topic: "<topic>" })\` to retrieve documentation.
|
|
14
|
+
|
|
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 |
|
|
22
|
+
|
|
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 |
|
|
30
|
+
|
|
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 |
|
|
38
|
+
|
|
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 |
|
|
45
|
+
|
|
46
|
+
## Integrations
|
|
47
|
+
| Topic | Description |
|
|
48
|
+
|-------|-------------|
|
|
49
|
+
| \`integrations\` | Cloud storage, Redis, security, and external APIs |
|
|
50
|
+
|
|
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 |
|
|
57
|
+
|
|
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 |
|
|
65
|
+
|
|
66
|
+
## Best Practices
|
|
67
|
+
| Topic | Description |
|
|
68
|
+
|-------|-------------|
|
|
69
|
+
| \`performance\` | Performance optimization best practices |
|
|
70
|
+
| \`security\` | Security best practices for authentication and authorization |
|
|
71
|
+
`;
|
|
72
|
+
}
|
|
@@ -45,19 +45,9 @@ project/
|
|
|
45
45
|
|
|
46
46
|
## Environment Variables
|
|
47
47
|
|
|
48
|
-
Access with `$env.<name>`.
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
| --------------------------- | ----------------------------- |
|
|
52
|
-
| `$env.$remote_ip` | Client IP address |
|
|
53
|
-
| `$env.$http_headers` | Request headers array |
|
|
54
|
-
| `$env.$request_uri` | Request URI |
|
|
55
|
-
| `$env.$request_method` | HTTP method (GET, POST, etc.) |
|
|
56
|
-
| `$env.$request_querystring` | Query string |
|
|
57
|
-
| `$env.$datasource` | Current datasource |
|
|
58
|
-
| `$env.$branch` | Current branch |
|
|
59
|
-
|
|
60
|
-
Custom environment variables are set in the Xano dashboard and accessed as `$env.MY_VAR`.
|
|
48
|
+
Access with `$env.<name>`. Common built-in variables include `$env.$remote_ip`, `$env.$http_headers`, `$env.$request_method`, `$env.$datasource`, and `$env.$branch`. Custom environment variables are set in the Xano dashboard and accessed as `$env.MY_VAR`.
|
|
49
|
+
|
|
50
|
+
For the complete list of system variables, see `xanoscript_docs({ topic: "syntax" })`.
|
|
61
51
|
|
|
62
52
|
## Core Syntax Patterns
|
|
63
53
|
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
---
|
|
2
|
+
applyTo: "ephemeral/**/*.xs"
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Ephemeral Environments
|
|
6
|
+
|
|
7
|
+
Temporary Xano workspaces for testing and one-off operations.
|
|
8
|
+
|
|
9
|
+
## Quick Reference
|
|
10
|
+
|
|
11
|
+
| Type | Purpose | Lifecycle |
|
|
12
|
+
|------|---------|-----------|
|
|
13
|
+
| **Service** | Temporary workspace with DB/APIs | Runs until shut down |
|
|
14
|
+
| **Job** | One-time operation | Executes once, then shuts down |
|
|
15
|
+
|
|
16
|
+
### Directory Structure
|
|
17
|
+
```
|
|
18
|
+
ephemeral/
|
|
19
|
+
├── my-service/
|
|
20
|
+
│ ├── workspace.xs
|
|
21
|
+
│ ├── tables/
|
|
22
|
+
│ ├── functions/
|
|
23
|
+
│ └── apis/
|
|
24
|
+
└── my-job/
|
|
25
|
+
├── workspace.xs
|
|
26
|
+
├── tables/
|
|
27
|
+
└── functions/
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Ephemeral Service
|
|
33
|
+
|
|
34
|
+
A temporary workspace with database, functions, and API endpoints.
|
|
35
|
+
|
|
36
|
+
### workspace.xs
|
|
37
|
+
```xs
|
|
38
|
+
workspace my_service {
|
|
39
|
+
env = {
|
|
40
|
+
api_key: "test-key"
|
|
41
|
+
debug: "true"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Table with Seed Data
|
|
47
|
+
```xs
|
|
48
|
+
table event {
|
|
49
|
+
auth = false
|
|
50
|
+
schema {
|
|
51
|
+
int id
|
|
52
|
+
timestamp created_at?=now
|
|
53
|
+
text name filters=trim
|
|
54
|
+
}
|
|
55
|
+
index = [
|
|
56
|
+
{type: "primary", field: [{name: "id"}]}
|
|
57
|
+
]
|
|
58
|
+
items = [
|
|
59
|
+
{"id": 1, "name": "Event 1"}
|
|
60
|
+
{"id": 2, "name": "Event 2"}
|
|
61
|
+
]
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### API Group
|
|
66
|
+
```xs
|
|
67
|
+
api_group events {
|
|
68
|
+
canonical = "events-api"
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Endpoints
|
|
73
|
+
```xs
|
|
74
|
+
query list verb=GET {
|
|
75
|
+
api_group = "events"
|
|
76
|
+
stack {
|
|
77
|
+
db.query event {
|
|
78
|
+
return = { type: "list" }
|
|
79
|
+
} as $events
|
|
80
|
+
}
|
|
81
|
+
response = $events
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
query add verb=POST {
|
|
85
|
+
api_group = "events"
|
|
86
|
+
input { text name filters=trim }
|
|
87
|
+
stack {
|
|
88
|
+
db.add event {
|
|
89
|
+
data = { name: $input.name }
|
|
90
|
+
} as $event
|
|
91
|
+
}
|
|
92
|
+
response = $event
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## Ephemeral Job
|
|
99
|
+
|
|
100
|
+
One-time operation with setup and cleanup hooks.
|
|
101
|
+
|
|
102
|
+
### Reserved Functions
|
|
103
|
+
| Function | Purpose | Required |
|
|
104
|
+
|----------|---------|----------|
|
|
105
|
+
| `$main` | Primary logic | Yes |
|
|
106
|
+
| `$pre` | Setup/validation | No |
|
|
107
|
+
| `$post` | Cleanup/notification | No |
|
|
108
|
+
|
|
109
|
+
### Execution Order
|
|
110
|
+
1. `$pre` (if defined)
|
|
111
|
+
2. `$main`
|
|
112
|
+
3. `$post` (if defined)
|
|
113
|
+
4. Environment shuts down
|
|
114
|
+
|
|
115
|
+
### $main Function
|
|
116
|
+
```xs
|
|
117
|
+
function "$main" {
|
|
118
|
+
input {
|
|
119
|
+
json args // Runtime arguments
|
|
120
|
+
json pre // Result from $pre
|
|
121
|
+
}
|
|
122
|
+
stack {
|
|
123
|
+
db.query authors {
|
|
124
|
+
return = { type: "count" }
|
|
125
|
+
} as $count
|
|
126
|
+
|
|
127
|
+
precondition ($count > 0) {
|
|
128
|
+
error = "No authors found"
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
db.add authors {
|
|
132
|
+
data = { name: "New Author" }
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
response = { processed: true }
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### $pre Function (optional)
|
|
140
|
+
```xs
|
|
141
|
+
function "$pre" {
|
|
142
|
+
input { json args }
|
|
143
|
+
stack {
|
|
144
|
+
// Validation or setup
|
|
145
|
+
precondition ($input.args.required_field != null) {
|
|
146
|
+
error = "Missing required field"
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
response = { validated: true }
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### $post Function (optional)
|
|
154
|
+
```xs
|
|
155
|
+
function "$post" {
|
|
156
|
+
input {
|
|
157
|
+
json args
|
|
158
|
+
json pre
|
|
159
|
+
json main
|
|
160
|
+
}
|
|
161
|
+
stack {
|
|
162
|
+
// Send notification or cleanup
|
|
163
|
+
api.request {
|
|
164
|
+
url = $env.WEBHOOK_URL
|
|
165
|
+
method = "POST"
|
|
166
|
+
params = {
|
|
167
|
+
status: "complete",
|
|
168
|
+
result: $input.main
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
response = null
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## Complete Service Example
|
|
179
|
+
|
|
180
|
+
```
|
|
181
|
+
ephemeral/event-tracker/
|
|
182
|
+
├── workspace.xs
|
|
183
|
+
├── tables/
|
|
184
|
+
│ └── event.xs
|
|
185
|
+
└── apis/
|
|
186
|
+
├── api_group.xs
|
|
187
|
+
├── list.xs
|
|
188
|
+
├── add.xs
|
|
189
|
+
└── clear.xs
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### workspace.xs
|
|
193
|
+
```xs
|
|
194
|
+
workspace event_tracker {
|
|
195
|
+
env = { api_key: "test" }
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### tables/event.xs
|
|
200
|
+
```xs
|
|
201
|
+
table event {
|
|
202
|
+
auth = false
|
|
203
|
+
schema {
|
|
204
|
+
int id
|
|
205
|
+
timestamp created_at?=now
|
|
206
|
+
text name
|
|
207
|
+
}
|
|
208
|
+
index = [
|
|
209
|
+
{type: "primary", field: [{name: "id"}]}
|
|
210
|
+
]
|
|
211
|
+
items = []
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### apis/list.xs
|
|
216
|
+
```xs
|
|
217
|
+
query list verb=GET {
|
|
218
|
+
api_group = "events"
|
|
219
|
+
stack {
|
|
220
|
+
db.query event {
|
|
221
|
+
sort = { created_at: "desc" }
|
|
222
|
+
return = { type: "list" }
|
|
223
|
+
} as $events
|
|
224
|
+
}
|
|
225
|
+
response = $events
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## Complete Job Example
|
|
232
|
+
|
|
233
|
+
```
|
|
234
|
+
ephemeral/data-migration/
|
|
235
|
+
├── workspace.xs
|
|
236
|
+
├── tables/
|
|
237
|
+
│ └── users.xs
|
|
238
|
+
└── functions/
|
|
239
|
+
├── $main.xs
|
|
240
|
+
└── $post.xs
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### workspace.xs
|
|
244
|
+
```xs
|
|
245
|
+
workspace data_migration {
|
|
246
|
+
env = { webhook_url: "https://webhook.site/xxx" }
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### tables/users.xs
|
|
251
|
+
```xs
|
|
252
|
+
table users {
|
|
253
|
+
auth = false
|
|
254
|
+
schema {
|
|
255
|
+
int id
|
|
256
|
+
text name
|
|
257
|
+
text email
|
|
258
|
+
timestamp migrated_at?
|
|
259
|
+
}
|
|
260
|
+
index = [
|
|
261
|
+
{type: "primary", field: [{name: "id"}]}
|
|
262
|
+
]
|
|
263
|
+
items = [
|
|
264
|
+
{"id": 1, "name": "Alice", "email": "alice@example.com"}
|
|
265
|
+
{"id": 2, "name": "Bob", "email": "bob@example.com"}
|
|
266
|
+
]
|
|
267
|
+
}
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### functions/$main.xs
|
|
271
|
+
```xs
|
|
272
|
+
function "$main" {
|
|
273
|
+
input { json args, json pre }
|
|
274
|
+
stack {
|
|
275
|
+
db.query users {
|
|
276
|
+
where = $db.users.migrated_at == null
|
|
277
|
+
} as $pending
|
|
278
|
+
|
|
279
|
+
foreach ($pending) {
|
|
280
|
+
each as $user {
|
|
281
|
+
db.edit users {
|
|
282
|
+
field_name = "id"
|
|
283
|
+
field_value = $user.id
|
|
284
|
+
data = { migrated_at: now }
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
response = { migrated: $pending|count }
|
|
290
|
+
}
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### functions/$post.xs
|
|
294
|
+
```xs
|
|
295
|
+
function "$post" {
|
|
296
|
+
input { json args, json pre, json main }
|
|
297
|
+
stack {
|
|
298
|
+
api.request {
|
|
299
|
+
url = $env.webhook_url
|
|
300
|
+
method = "POST"
|
|
301
|
+
params = { result: $input.main }
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
response = null
|
|
305
|
+
}
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
## Deploying
|
|
311
|
+
|
|
312
|
+
### Deploy Service
|
|
313
|
+
```
|
|
314
|
+
publish_ephemeral_service name="my-api" directory="ephemeral/my-service" mode="service"
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### Run Job
|
|
318
|
+
```
|
|
319
|
+
publish_ephemeral_service name="migration" directory="ephemeral/my-job" mode="job"
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
---
|
|
323
|
+
|
|
324
|
+
## Best Practices
|
|
325
|
+
|
|
326
|
+
1. **Keep isolated** - Self-contained with own tables/functions
|
|
327
|
+
2. **Seed test data** - Use `items` in table definitions
|
|
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`
|