@xano/developer-mcp 1.0.0
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/LICENSE +21 -0
- package/README.md +261 -0
- package/api_docs/addon.md +193 -0
- package/api_docs/agent.md +154 -0
- package/api_docs/api_group.md +236 -0
- package/api_docs/authentication.md +68 -0
- package/api_docs/file.md +190 -0
- package/api_docs/function.md +217 -0
- package/api_docs/history.md +263 -0
- package/api_docs/index.md +104 -0
- package/api_docs/mcp_server.md +139 -0
- package/api_docs/middleware.md +205 -0
- package/api_docs/realtime.md +153 -0
- package/api_docs/table.md +151 -0
- package/api_docs/task.md +191 -0
- package/api_docs/tool.md +216 -0
- package/api_docs/triggers.md +344 -0
- package/api_docs/workspace.md +246 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +495 -0
- package/package.json +49 -0
- package/xanoscript_docs/README.md +1 -0
- package/xanoscript_docs/api_query_examples.md +1255 -0
- package/xanoscript_docs/api_query_guideline.md +129 -0
- package/xanoscript_docs/build_from_lovable.md +715 -0
- package/xanoscript_docs/db_query_guideline.md +427 -0
- package/xanoscript_docs/ephemeral_environment_guideline.md +529 -0
- package/xanoscript_docs/expression_guideline.md +1086 -0
- package/xanoscript_docs/frontend_guideline.md +67 -0
- package/xanoscript_docs/function_examples.md +1406 -0
- package/xanoscript_docs/function_guideline.md +130 -0
- package/xanoscript_docs/functions.md +2155 -0
- package/xanoscript_docs/input_guideline.md +227 -0
- package/xanoscript_docs/mcp_server_examples.md +36 -0
- package/xanoscript_docs/mcp_server_guideline.md +69 -0
- package/xanoscript_docs/query_filter.md +489 -0
- package/xanoscript_docs/table_examples.md +586 -0
- package/xanoscript_docs/table_guideline.md +137 -0
- package/xanoscript_docs/task_examples.md +511 -0
- package/xanoscript_docs/task_guideline.md +103 -0
- package/xanoscript_docs/tips_and_tricks.md +144 -0
- package/xanoscript_docs/tool_examples.md +69 -0
- package/xanoscript_docs/tool_guideline.md +139 -0
- package/xanoscript_docs/unit_testing_guideline.md +328 -0
- package/xanoscript_docs/version.json +3 -0
- package/xanoscript_docs/workspace.md +17 -0
|
@@ -0,0 +1,511 @@
|
|
|
1
|
+
---
|
|
2
|
+
applyTo: "tasks/*.xs"
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Xanoscript Task Examples
|
|
6
|
+
|
|
7
|
+
Below are some examples of tasks defined in Xanoscript.
|
|
8
|
+
|
|
9
|
+
## deactivate_user_profile_task
|
|
10
|
+
|
|
11
|
+
```xs
|
|
12
|
+
task "deactivate_inactive_profiles" {
|
|
13
|
+
description = "Deactivate user profiles for users who have not had session activity in the past 30 days. This task runs monthly."
|
|
14
|
+
stack {
|
|
15
|
+
var $current_time {
|
|
16
|
+
value = now
|
|
17
|
+
description = "Get the current timestamp for comparison"
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
var $threshold_time {
|
|
21
|
+
value = $current_time - (30 * 86400 * 1000)
|
|
22
|
+
description = "Calculate the timestamp for 30 days ago"
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
db.query "sessions" {
|
|
26
|
+
description = "Find users with no session activity in the past 30 days"
|
|
27
|
+
where = $db.sessions.last_activity < $threshold_time
|
|
28
|
+
output = ["id", "user_id", "is_active"]
|
|
29
|
+
} as $inactive_users
|
|
30
|
+
|
|
31
|
+
foreach ($inactive_users) {
|
|
32
|
+
each as $user {
|
|
33
|
+
db.edit "user_profile" {
|
|
34
|
+
field_name = "id"
|
|
35
|
+
field_value = $user.user_id
|
|
36
|
+
data = {is_active: false}
|
|
37
|
+
description = "Deactivate user profile"
|
|
38
|
+
} as $user_profile
|
|
39
|
+
|
|
40
|
+
debug.log {
|
|
41
|
+
value = "Deactivated user profile with ID: " ~ $var.user_profileuser.user_id
|
|
42
|
+
description = "Log individual profile deactivation"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
debug.log {
|
|
48
|
+
value = "Profile deactivation task completed. Total profiles deactivated: " ~ $inactive_users|count
|
|
49
|
+
description = "Log successful task completion"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
schedule = [{starts_on: 2025-07-01 00:00:00+0000, freq: 2592000}]
|
|
54
|
+
|
|
55
|
+
history = "inherit"
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## cleanup_expired_sessions_task
|
|
60
|
+
|
|
61
|
+
```xs
|
|
62
|
+
task "cleanup_expired_sessions" {
|
|
63
|
+
description = "Clean up expired sessions from the sessions table every 6 hours starting Feb 1, 2026. This task deletes expired sessions and logs the number of deletions for monitoring purposes."
|
|
64
|
+
stack {
|
|
65
|
+
var $current_time {
|
|
66
|
+
value = now
|
|
67
|
+
description = "Get the current timestamp for comparison"
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
db.query "sessions" {
|
|
71
|
+
description = "Count expired sessions before deletion"
|
|
72
|
+
where = $db.sessions.expires_at < $current_time && $db.sessions.is_active
|
|
73
|
+
} as $expired_sessions
|
|
74
|
+
|
|
75
|
+
var $expired_count {
|
|
76
|
+
value = $expired_sessions|count
|
|
77
|
+
description = "Count of expired sessions to be deleted"
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
var $total_deletions {
|
|
81
|
+
value = 0
|
|
82
|
+
description = "Track the total number of sessions deleted"
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
debug.log {
|
|
86
|
+
value = "Found " ~ $expired_count ~ " expired sessions for cleanup"
|
|
87
|
+
description = "Log count of sessions found for deletion"
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
foreach ($expired_sessions) {
|
|
91
|
+
each as $session {
|
|
92
|
+
db.del sessions {
|
|
93
|
+
field_name = "id"
|
|
94
|
+
field_value = $session.id
|
|
95
|
+
description = "Delete expired session"
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
math.add $total_deletions {
|
|
99
|
+
value = 1
|
|
100
|
+
description = "Increment deletion counter"
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
debug.log {
|
|
104
|
+
value = "Deleted session with ID: " ~ $session.id
|
|
105
|
+
description = "Log individual session deletion"
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
debug.log {
|
|
111
|
+
value = "Session cleanup completed. Total sessions deleted: " ~ $total_deletions
|
|
112
|
+
description = "Log successful cleanup completion"
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
schedule = [{starts_on: 2026-02-01 00:00:00+0000, freq: 21600}]
|
|
117
|
+
|
|
118
|
+
history = 1000
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## slack_prompts_gif_finder
|
|
123
|
+
|
|
124
|
+
```xs
|
|
125
|
+
task "slack_prompts_gif_finder" {
|
|
126
|
+
description = "Find and populate GIF URLs for Slack prompts using AI completion"
|
|
127
|
+
stack {
|
|
128
|
+
debug.log {
|
|
129
|
+
value = "Starting GIF URL population task"
|
|
130
|
+
description = "Log task start"
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
db.query "slack_prompts" {
|
|
134
|
+
description = "Retrieve prompts that are missing a GIF URL"
|
|
135
|
+
where = $db.slack_prompts.gif_url == "" && $db.slack_prompts.prompt != ""
|
|
136
|
+
} as $prompts_without_gifs
|
|
137
|
+
|
|
138
|
+
debug.log {
|
|
139
|
+
value = {
|
|
140
|
+
count: ($prompts_without_gifs|count)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
description = "Log prompts found"
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
conditional {
|
|
147
|
+
description = "Process if prompts exist"
|
|
148
|
+
if (($prompts_without_gifs|count) > 0) {
|
|
149
|
+
var $processed {
|
|
150
|
+
value = 0
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
foreach ($prompts_without_gifs) {
|
|
154
|
+
each as $prompt {
|
|
155
|
+
util.template_engine {
|
|
156
|
+
value = """
|
|
157
|
+
Based on the following Slack message, suggest a single search query of 2-3 words for finding a funny GIF on Giphy. Your response should *ONLY* include the search term. Do not included any other explanation in your response.
|
|
158
|
+
|
|
159
|
+
Message:
|
|
160
|
+
{{$prompt.prompt}}
|
|
161
|
+
"""
|
|
162
|
+
|
|
163
|
+
description = "Gemini Prompt"
|
|
164
|
+
} as $ai_request
|
|
165
|
+
|
|
166
|
+
var $search_term {
|
|
167
|
+
value = "cute dog"
|
|
168
|
+
description = "Set the fallback search term"
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
try_catch {
|
|
172
|
+
description = "Get AI suggestion"
|
|
173
|
+
try {
|
|
174
|
+
function.run "ai/Gemini: Simple Chat Completion" {
|
|
175
|
+
description = "Use Gemini to convert the Slack prompt into a search term for Giphy"
|
|
176
|
+
input = {model: "gemini-2.5-flash", message: $ai_request}
|
|
177
|
+
} as $ai_result
|
|
178
|
+
|
|
179
|
+
var.update $search_term {
|
|
180
|
+
value = $ai_result
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
catch {
|
|
185
|
+
debug.log {
|
|
186
|
+
value = "AI request failed, using fallback"
|
|
187
|
+
description = "Log AI failure"
|
|
188
|
+
errorCode = $error.code
|
|
189
|
+
errorMessage = $error.message
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
try_catch {
|
|
195
|
+
description = "Search Giphy"
|
|
196
|
+
try {
|
|
197
|
+
api.request {
|
|
198
|
+
url = "https://api.giphy.com/v1/gifs/search"
|
|
199
|
+
method = "GET"
|
|
200
|
+
params = {
|
|
201
|
+
api_key: $env.giphy_key
|
|
202
|
+
q: $search_term
|
|
203
|
+
limit: 1
|
|
204
|
+
rating: "g"
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
verify_host = false
|
|
208
|
+
verify_peer = false
|
|
209
|
+
description = "Giphy search"
|
|
210
|
+
} as $gif_result
|
|
211
|
+
|
|
212
|
+
var.update $gif_result {
|
|
213
|
+
value = $gif_result.response.result
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
conditional {
|
|
217
|
+
description = "Update if GIF found"
|
|
218
|
+
if (($gif_result.data|count) > 0) {
|
|
219
|
+
var $gif_url {
|
|
220
|
+
value = ($gif_result.data|first).images.original.url
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
db.edit "slack_prompts" {
|
|
224
|
+
field_name = "id"
|
|
225
|
+
field_value = $prompt.id
|
|
226
|
+
data = {gif_url: $gif_url}
|
|
227
|
+
description = "Update the GIF URL and updated_at for the prompt"
|
|
228
|
+
} as $updated_record
|
|
229
|
+
|
|
230
|
+
debug.log {
|
|
231
|
+
value = {
|
|
232
|
+
id: $var.updated_record.id
|
|
233
|
+
gif_url: $var.updated_record.gif_url
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
description = "GIF URL added"
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
catch {
|
|
243
|
+
debug.log {
|
|
244
|
+
value = {
|
|
245
|
+
id: $var.updated_record.id
|
|
246
|
+
error: "Giphy search failed"
|
|
247
|
+
errorCode = $error.code
|
|
248
|
+
errorMessage = $error.message
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
description = "Giphy error"
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
var.update $processed {
|
|
257
|
+
value = $var.processed + 1
|
|
258
|
+
description = "Increment the processed counter"
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
debug.log {
|
|
264
|
+
value = {
|
|
265
|
+
processed: $var.processed
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
description = "Processing complete"
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
else {
|
|
273
|
+
debug.log {
|
|
274
|
+
value = "No prompts need GIFs"
|
|
275
|
+
description = "Nothing to process"
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
debug.log {
|
|
281
|
+
value = "Task completed"
|
|
282
|
+
description = "Task end"
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
schedule = [{starts_on: 2026-01-14 09:00:00+0000, freq: 86400}]
|
|
287
|
+
|
|
288
|
+
history = "inherit"
|
|
289
|
+
}
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
## scheduled_end_of_month_task
|
|
293
|
+
|
|
294
|
+
```xs
|
|
295
|
+
task "end_of_month_task" {
|
|
296
|
+
stack {
|
|
297
|
+
var $timezone {
|
|
298
|
+
value = "UTC"
|
|
299
|
+
description = "Set Timezone"
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
var $now {
|
|
303
|
+
value = now
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
var $today {
|
|
307
|
+
value = $now|format_timestamp:"Y-m-d":$timezone
|
|
308
|
+
description = "Today"
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
var $end_of_month {
|
|
312
|
+
value = $now|transform_timestamp:"last day of this month":$timezone|format_timestamp:"Y-m-d":$timezone
|
|
313
|
+
description = "Last day of this month"
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
conditional {
|
|
317
|
+
description = "If Today is NOT the last day of the month, stop running"
|
|
318
|
+
if ($today != $end_of_month) {
|
|
319
|
+
return {
|
|
320
|
+
value = "Today is not the last day of the month. Stop running."
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
debug.log {
|
|
326
|
+
value = "It's the end of the month... executing task..."
|
|
327
|
+
description = "Beginning of end of month task"
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
schedule = [{starts_on: 2026-05-01 23:00:00+0000, freq: 86400}]
|
|
332
|
+
|
|
333
|
+
history = "all"
|
|
334
|
+
}
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
## subscription_renewal_reminder_task
|
|
338
|
+
|
|
339
|
+
```xs
|
|
340
|
+
task "subscription_renewal_reminder" {
|
|
341
|
+
stack {
|
|
342
|
+
var $current_time {
|
|
343
|
+
value = now
|
|
344
|
+
description = "Current timestamp for calculations"
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
debug.log {
|
|
348
|
+
value = "Starting subscription renewal reminder task"
|
|
349
|
+
description = "Log task start"
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
db.query "subscription" {
|
|
353
|
+
description = "Query subscriptions expiring in next 7 days"
|
|
354
|
+
where = $db.subscription.status == "active" && $db.subscription.end_date > $current_time && $db.subscription.end_date <= ($current_time + 604800000)
|
|
355
|
+
} as $expiring_subscriptions
|
|
356
|
+
|
|
357
|
+
foreach ($expiring_subscriptions) {
|
|
358
|
+
each as $subscription {
|
|
359
|
+
db.query "user" {
|
|
360
|
+
description = "Get user details"
|
|
361
|
+
where = $db.user.id == $subscription.user_id
|
|
362
|
+
} as $user_result
|
|
363
|
+
|
|
364
|
+
conditional {
|
|
365
|
+
description = "Process if user found"
|
|
366
|
+
if (($user_result|count) > 0) {
|
|
367
|
+
var $user {
|
|
368
|
+
value = $user_result|first
|
|
369
|
+
description = "Extract user from result"
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
api.request {
|
|
373
|
+
url = "https://mandrillapp.com/api/1.0/messages/send"
|
|
374
|
+
method = "POST"
|
|
375
|
+
params = {}|set:"key":$env.mandrill_api_key|set:"message":({}|set:"from_email":"noreply@example.com"|set:"subject":"Subscription Reminder"|set:"text":"Your subscription expires soon"|set:"to":([]|push:({}|set:"email":$user.email|set:"type":"to")))
|
|
376
|
+
headers = []|push:"Content-Type: application/json"
|
|
377
|
+
description = "Send email reminder"
|
|
378
|
+
} as $email_response
|
|
379
|
+
|
|
380
|
+
db.add notification_log {
|
|
381
|
+
data = {
|
|
382
|
+
created_at : $current_time
|
|
383
|
+
user_id : $user.id
|
|
384
|
+
notification_type: "subscription_renewal_reminder"
|
|
385
|
+
title : "Subscription Reminder"
|
|
386
|
+
message : "Reminder sent successfully"
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
description = "Log notification"
|
|
390
|
+
} as $log_entry
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
debug.log {
|
|
397
|
+
value = "Task completed"
|
|
398
|
+
description = "Log completion"
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
schedule = [{starts_on: 2026-01-01 09:00:00+0000, freq: 86400}]
|
|
403
|
+
|
|
404
|
+
history = "all"
|
|
405
|
+
}
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
## low_stock_alert
|
|
409
|
+
|
|
410
|
+
```xs
|
|
411
|
+
task "low_stock_alert" {
|
|
412
|
+
stack {
|
|
413
|
+
db.query "product" {
|
|
414
|
+
description = "Fetch products with stock quantity below 10"
|
|
415
|
+
where = $db.product.stock_quantity < 10
|
|
416
|
+
} as $low_stock_products
|
|
417
|
+
|
|
418
|
+
var $alert_count {
|
|
419
|
+
value = 0
|
|
420
|
+
description = "Counter for alerted products"
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
foreach ($low_stock_products) {
|
|
424
|
+
each as $product {
|
|
425
|
+
api.realtime_event {
|
|
426
|
+
channel = "stock_channel"
|
|
427
|
+
data = {product_id: $product.id, stock_quantity: $product.stock_quantity}
|
|
428
|
+
auth_table = "user"
|
|
429
|
+
auth_id = "123"
|
|
430
|
+
description = "Send real-time notification for low stock product"
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
math.add $alert_count {
|
|
434
|
+
value = 1
|
|
435
|
+
description = "Increment alert count"
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
debug.log {
|
|
441
|
+
value = $alert_count
|
|
442
|
+
description = "Log the number of alerted products"
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
schedule = [{starts_on: 2026-01-01 09:00:00+0000, freq: 86400}]
|
|
447
|
+
|
|
448
|
+
history = "inherit"
|
|
449
|
+
}
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
## daily_sales_report_task
|
|
453
|
+
|
|
454
|
+
```xs
|
|
455
|
+
task "daily_sales_report" {
|
|
456
|
+
description = "Daily at 11 PM UTC generate a sales report by querying all payment transactions from the past 24 hours and calculating the total sales amount and transaction count. The task automatically executes every day starting from May 1, 2026, providing a summary of daily sales performance."
|
|
457
|
+
stack {
|
|
458
|
+
var $twenty_four_hours_ago {
|
|
459
|
+
value = (now|transform_timestamp:"24 hours ago":"UTC")
|
|
460
|
+
description = "Calculate timestamp for 24 hours ago"
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
db.query "payment_transactions" {
|
|
464
|
+
description = "Get all transactions from the past 24 hours"
|
|
465
|
+
where = $db.payment_transactions.transaction_date >= $twenty_four_hours_ago
|
|
466
|
+
} as $daily_sales
|
|
467
|
+
|
|
468
|
+
var $transaction_count {
|
|
469
|
+
value = $daily_sales|count
|
|
470
|
+
description = "Count number of transactions"
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
var $total_sales {
|
|
474
|
+
value = ($daily_sales[$$].amount)|sum
|
|
475
|
+
description = "Initialize total sales amount"
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
var $report_date {
|
|
479
|
+
value = now
|
|
480
|
+
description = "Current timestamp for the report"
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
db.transaction {
|
|
484
|
+
description = "Store daily sales report with data consistency"
|
|
485
|
+
stack {
|
|
486
|
+
db.add reports {
|
|
487
|
+
data = {
|
|
488
|
+
report_type : "daily_sales"
|
|
489
|
+
report_date : $report_date
|
|
490
|
+
total_sales : $total_sales
|
|
491
|
+
transaction_count: $transaction_count
|
|
492
|
+
period_start : $twenty_four_hours_ago
|
|
493
|
+
period_end : $report_date
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
description = "Insert daily sales report into reports table"
|
|
497
|
+
} as $report_result
|
|
498
|
+
|
|
499
|
+
debug.log {
|
|
500
|
+
value = "Daily sales report generated successfully"
|
|
501
|
+
description = "Log successful report generation"
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
schedule = [{starts_on: 2026-05-01 23:00:00+0000, freq: 86400}]
|
|
508
|
+
|
|
509
|
+
history = "inherit"
|
|
510
|
+
}
|
|
511
|
+
```
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
---
|
|
2
|
+
applyTo: "tasks/*.xs"
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# How to Define Tasks in XanoScript
|
|
6
|
+
|
|
7
|
+
A **task** in XanoScript is a scheduled job that automates operations at specific times or intervals. Tasks are created in the `tasks` folder and are ideal for recurring jobs like data cleanup, report generation, or sending notifications.
|
|
8
|
+
|
|
9
|
+
## Task Structure
|
|
10
|
+
|
|
11
|
+
A task file consists of:
|
|
12
|
+
|
|
13
|
+
- The task name (e.g., `daily_report`, `cleanup_expired_sessions`)
|
|
14
|
+
- An optional `description` field
|
|
15
|
+
- A `stack` block containing the logic to execute
|
|
16
|
+
- A `schedule` block specifying when the task runs
|
|
17
|
+
|
|
18
|
+
## Example Task
|
|
19
|
+
|
|
20
|
+
The following task would be stored in `tasks/daily_sales_report.xs`
|
|
21
|
+
|
|
22
|
+
```xs
|
|
23
|
+
task "daily_sales_report" {
|
|
24
|
+
description = "Generate a daily sales report at 11 PM UTC"
|
|
25
|
+
stack {
|
|
26
|
+
db.query "payment_transactions" {
|
|
27
|
+
description = "Get all transactions from the past 24 hours"
|
|
28
|
+
where = $db.payment_transactions.transaction_date >= (now|transform_timestamp:"24 hours ago":"UTC")
|
|
29
|
+
} as $daily_sales
|
|
30
|
+
|
|
31
|
+
var $transaction_count {
|
|
32
|
+
value = $daily_sales|count
|
|
33
|
+
description = "Count number of transactions"
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
var $total_sales {
|
|
37
|
+
value = ($daily_sales[$$].amount)|sum
|
|
38
|
+
description = "Calculate total sales amount"
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
db.add reports {
|
|
42
|
+
data = {
|
|
43
|
+
report_type : "daily_sales"
|
|
44
|
+
report_date : now
|
|
45
|
+
total_sales : $total_sales
|
|
46
|
+
transaction_count: $transaction_count
|
|
47
|
+
}
|
|
48
|
+
description = "Insert daily sales report"
|
|
49
|
+
} as $report_result
|
|
50
|
+
|
|
51
|
+
debug.log {
|
|
52
|
+
value = "Daily sales report generated"
|
|
53
|
+
description = "Log report generation"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
schedule = [{starts_on: 2026-05-01 23:00:00+0000, freq: 86400}]
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Stack Block
|
|
62
|
+
|
|
63
|
+
The `stack` block contains the sequence of actions to perform, such as:
|
|
64
|
+
|
|
65
|
+
- Database queries (`db.query`, `db.add`, `db.edit`, `db.patch` etc.)
|
|
66
|
+
- Variable declarations (`var`)
|
|
67
|
+
- Control flow (`foreach`, `conditional`)
|
|
68
|
+
- Logging (`debug.log`)
|
|
69
|
+
- API calls (`api.request`)
|
|
70
|
+
|
|
71
|
+
## Schedule Block
|
|
72
|
+
|
|
73
|
+
The `schedule` block defines when the task runs. It uses an `events` array with:
|
|
74
|
+
|
|
75
|
+
- `starts_on`: Start date and time (e.g., `2026-05-01 23:00:00+0000`)
|
|
76
|
+
- `freq`: Frequency in seconds (e.g., `86400` for daily)
|
|
77
|
+
- `ends_on`: Optional end date
|
|
78
|
+
|
|
79
|
+
**Example:**
|
|
80
|
+
|
|
81
|
+
```xs
|
|
82
|
+
schedule {
|
|
83
|
+
events = [
|
|
84
|
+
{starts_on: 2026-05-01 23:00:00+0000, freq: 86400}
|
|
85
|
+
]
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Best Practices
|
|
90
|
+
|
|
91
|
+
- Use `description` fields to document the purpose of your task and each block.
|
|
92
|
+
- Place all logic inside the `stack` block.
|
|
93
|
+
- Use the `schedule` block to automate execution.
|
|
94
|
+
- Use logging (`debug.log`) to track task execution and outcomes.
|
|
95
|
+
|
|
96
|
+
## Summary
|
|
97
|
+
|
|
98
|
+
- Place tasks in the `tasks` folder.
|
|
99
|
+
- Use the `stack` block for job logic.
|
|
100
|
+
- Use the `schedule` block for timing.
|
|
101
|
+
- Document your task with `description` fields.
|
|
102
|
+
|
|
103
|
+
For more examples, see the documentation or sample tasks in your
|