lua-cli 3.0.0-alpha.1 → 3.0.0-alpha.5
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/api/job.api.service.d.ts +16 -7
- package/dist/api/job.api.service.js +21 -5
- package/dist/api/postprocessor.api.service.d.ts +61 -1
- package/dist/api/postprocessor.api.service.js +35 -0
- package/dist/api/preprocessor.api.service.d.ts +61 -1
- package/dist/api/preprocessor.api.service.js +35 -0
- package/dist/api-exports.d.ts +26 -6
- package/dist/api-exports.js +42 -29
- package/dist/cli/command-definitions.js +13 -6
- package/dist/commands/chat.js +32 -5
- package/dist/commands/compile.js +16 -2
- package/dist/commands/dev.js +23 -2
- package/dist/commands/push.d.ts +6 -2
- package/dist/commands/push.js +412 -6
- package/dist/commands/test.js +18 -2
- package/dist/common/job.instance.d.ts +3 -0
- package/dist/common/job.instance.js +8 -0
- package/dist/config/constants.d.ts +6 -5
- package/dist/config/constants.js +12 -10
- package/dist/interfaces/chat.d.ts +30 -1
- package/dist/interfaces/jobs.d.ts +21 -0
- package/dist/types/skill.d.ts +75 -56
- package/dist/types/skill.js +53 -59
- package/dist/utils/bundling.d.ts +13 -4
- package/dist/utils/bundling.js +83 -26
- package/dist/utils/compile.js +27 -6
- package/dist/utils/dev-api.d.ts +42 -2
- package/dist/utils/dev-api.js +177 -4
- package/dist/utils/dev-server.d.ts +1 -1
- package/dist/utils/dev-server.js +4 -4
- package/dist/utils/dynamic-job-bundler.d.ts +17 -0
- package/dist/utils/dynamic-job-bundler.js +143 -0
- package/dist/utils/pre-bundle-jobs.d.ts +26 -0
- package/dist/utils/pre-bundle-jobs.js +176 -0
- package/dist/utils/sandbox-storage.d.ts +48 -0
- package/dist/utils/sandbox-storage.js +114 -0
- package/dist/utils/sandbox.d.ts +2 -2
- package/dist/utils/sandbox.js +23 -7
- package/package.json +1 -1
- package/template/lua.skill.yaml +47 -0
- package/template/package-lock.json +10505 -0
- package/template/package.json +2 -1
- package/template/src/index.ts +65 -3
- package/template/src/tools/CreateInlineJob.ts +42 -0
- package/API_REFERENCE.md +0 -1408
- package/CHANGELOG.md +0 -236
- package/CLI_REFERENCE.md +0 -908
- package/GETTING_STARTED.md +0 -1040
- package/INSTANCE_TYPES.md +0 -1158
- package/README.md +0 -865
- package/TEMPLATE_GUIDE.md +0 -1398
- package/USER_DATA_INSTANCE.md +0 -621
- package/template/AGENT_CONFIGURATION.md +0 -251
- package/template/COMPLEX_JOB_EXAMPLES.md +0 -795
- package/template/DYNAMIC_JOB_CREATION.md +0 -371
- package/template/TOOL_EXAMPLES.md +0 -655
- package/template/WEBHOOKS_JOBS_QUICKSTART.md +0 -318
- package/template/WEBHOOK_JOB_EXAMPLES.md +0 -817
- package/template/src/index-agent-example.ts +0 -201
- package/template/src/postprocessors/ResponseFormatter.ts +0 -151
- package/template/src/preprocessors/MessageFilter.ts +0 -91
|
@@ -1,817 +0,0 @@
|
|
|
1
|
-
# Webhook & Job Examples
|
|
2
|
-
|
|
3
|
-
Complete examples for creating webhooks, scheduled jobs, and dynamic job creation from tools.
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## 📋 Table of Contents
|
|
8
|
-
|
|
9
|
-
- [Webhook Examples](#webhook-examples)
|
|
10
|
-
- [User Event Webhook](#1-user-event-webhook)
|
|
11
|
-
- [Payment Webhook](#2-payment-webhook)
|
|
12
|
-
- [Job Examples](#job-examples)
|
|
13
|
-
- [Daily Cleanup Job](#1-daily-cleanup-job)
|
|
14
|
-
- [Health Check Job](#2-health-check-job)
|
|
15
|
-
- [Data Migration Job](#3-data-migration-job)
|
|
16
|
-
- [Abandoned Basket Processor](#4-abandoned-basket-processor-job)
|
|
17
|
-
- [Dynamic Job Creation](#dynamic-job-creation)
|
|
18
|
-
- [Smart Basket Tool](#smart-basket-tool)
|
|
19
|
-
- [Complete Integration Example](#complete-integration-example)
|
|
20
|
-
|
|
21
|
-
---
|
|
22
|
-
|
|
23
|
-
## Webhook Examples
|
|
24
|
-
|
|
25
|
-
Webhooks are HTTP endpoints that receive requests from external systems.
|
|
26
|
-
|
|
27
|
-
### 1. User Event Webhook
|
|
28
|
-
|
|
29
|
-
**File:** `src/webhooks/UserEventWebhook.ts`
|
|
30
|
-
|
|
31
|
-
**What it does:** Receives user events from external systems (CRM, marketing tools, etc.).
|
|
32
|
-
|
|
33
|
-
**Use cases:**
|
|
34
|
-
- User signup notifications from external auth systems
|
|
35
|
-
- Profile updates from CRM
|
|
36
|
-
- User deletion events for GDPR compliance
|
|
37
|
-
|
|
38
|
-
**Key features:**
|
|
39
|
-
- ✅ Query parameter validation (source tracking)
|
|
40
|
-
- ✅ Header validation (API key security)
|
|
41
|
-
- ✅ Body validation (event data)
|
|
42
|
-
- ✅ Stores events in custom data
|
|
43
|
-
|
|
44
|
-
**Code highlights:**
|
|
45
|
-
```typescript
|
|
46
|
-
const webhook = new LuaWebhook({
|
|
47
|
-
name: "user-events",
|
|
48
|
-
|
|
49
|
-
// Optional query params for tracking
|
|
50
|
-
querySchema: z.object({
|
|
51
|
-
source: z.string().optional()
|
|
52
|
-
}),
|
|
53
|
-
|
|
54
|
-
// Require API key in headers
|
|
55
|
-
headerSchema: z.object({
|
|
56
|
-
'x-api-key': z.string()
|
|
57
|
-
}),
|
|
58
|
-
|
|
59
|
-
// Event data validation
|
|
60
|
-
bodySchema: z.object({
|
|
61
|
-
eventType: z.enum(['signup', 'update', 'delete']),
|
|
62
|
-
userId: z.string(),
|
|
63
|
-
email: z.string().email()
|
|
64
|
-
}),
|
|
65
|
-
|
|
66
|
-
execute: async ({ query, headers, body }) => {
|
|
67
|
-
// Validate API key
|
|
68
|
-
if (headers['x-api-key'] !== expectedKey) {
|
|
69
|
-
throw new Error('Invalid API key');
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// Store event
|
|
73
|
-
await Data.create('user-events', {
|
|
74
|
-
...body,
|
|
75
|
-
source: query?.source,
|
|
76
|
-
receivedAt: new Date().toISOString()
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
return { success: true };
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
**How to call it:**
|
|
85
|
-
```bash
|
|
86
|
-
curl -X POST \
|
|
87
|
-
https://api.heylua.ai/webhooks/{agentId}/{webhookId} \
|
|
88
|
-
-H "Content-Type: application/json" \
|
|
89
|
-
-H "x-api-key: your-secret-key" \
|
|
90
|
-
-d '{
|
|
91
|
-
"eventType": "signup",
|
|
92
|
-
"userId": "user_123",
|
|
93
|
-
"email": "new@example.com"
|
|
94
|
-
}'
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
---
|
|
98
|
-
|
|
99
|
-
### 2. Payment Webhook
|
|
100
|
-
|
|
101
|
-
**File:** `src/webhooks/PaymentWebhook.ts`
|
|
102
|
-
|
|
103
|
-
**What it does:** Receives payment notifications from Stripe, PayPal, etc.
|
|
104
|
-
|
|
105
|
-
**Use cases:**
|
|
106
|
-
- Payment confirmation processing
|
|
107
|
-
- Order status updates
|
|
108
|
-
- Failed payment handling
|
|
109
|
-
- Transaction logging
|
|
110
|
-
|
|
111
|
-
**Key features:**
|
|
112
|
-
- ✅ Stripe signature validation (security)
|
|
113
|
-
- ✅ Multiple event type handling
|
|
114
|
-
- ✅ Order status updates
|
|
115
|
-
- ✅ Payment logging
|
|
116
|
-
|
|
117
|
-
**Code highlights:**
|
|
118
|
-
```typescript
|
|
119
|
-
const webhook = new LuaWebhook({
|
|
120
|
-
name: "payment-notifications",
|
|
121
|
-
|
|
122
|
-
headerSchema: z.object({
|
|
123
|
-
'stripe-signature': z.string().optional()
|
|
124
|
-
}),
|
|
125
|
-
|
|
126
|
-
bodySchema: z.object({
|
|
127
|
-
type: z.string(),
|
|
128
|
-
data: z.object({
|
|
129
|
-
object: z.object({
|
|
130
|
-
id: z.string(),
|
|
131
|
-
amount: z.number(),
|
|
132
|
-
metadata: z.object({
|
|
133
|
-
orderId: z.string().optional()
|
|
134
|
-
}).optional()
|
|
135
|
-
})
|
|
136
|
-
})
|
|
137
|
-
}),
|
|
138
|
-
|
|
139
|
-
execute: async ({ body }) => {
|
|
140
|
-
if (body.type === 'payment_intent.succeeded') {
|
|
141
|
-
// Update order status
|
|
142
|
-
if (body.data.object.metadata?.orderId) {
|
|
143
|
-
await Orders.updateStatus('confirmed',
|
|
144
|
-
body.data.object.metadata.orderId);
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// Log payment
|
|
148
|
-
await Data.create('payment-logs', {
|
|
149
|
-
paymentId: body.data.object.id,
|
|
150
|
-
amount: body.data.object.amount,
|
|
151
|
-
status: 'succeeded'
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
return { success: true };
|
|
156
|
-
}
|
|
157
|
-
});
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
**Stripe integration:**
|
|
161
|
-
```typescript
|
|
162
|
-
// In Stripe dashboard, configure webhook URL:
|
|
163
|
-
// https://api.heylua.ai/webhooks/{agentId}/{webhookId}
|
|
164
|
-
|
|
165
|
-
// Select events to send:
|
|
166
|
-
// - payment_intent.succeeded
|
|
167
|
-
// - payment_intent.payment_failed
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
---
|
|
171
|
-
|
|
172
|
-
## Job Examples
|
|
173
|
-
|
|
174
|
-
Jobs are scheduled tasks that run at specific times or intervals.
|
|
175
|
-
|
|
176
|
-
### 1. Daily Cleanup Job
|
|
177
|
-
|
|
178
|
-
**File:** `src/jobs/DailyCleanupJob.ts`
|
|
179
|
-
|
|
180
|
-
**What it does:** Runs daily at 2 AM to clean up old data.
|
|
181
|
-
|
|
182
|
-
**Use cases:**
|
|
183
|
-
- Remove old logs
|
|
184
|
-
- Archive expired data
|
|
185
|
-
- Database maintenance
|
|
186
|
-
- Cost optimization
|
|
187
|
-
|
|
188
|
-
**Schedule:** Cron (daily at 2 AM EST)
|
|
189
|
-
|
|
190
|
-
**Key features:**
|
|
191
|
-
- ✅ Cron scheduling with timezone
|
|
192
|
-
- ✅ Multiple data collection cleanup
|
|
193
|
-
- ✅ Retry on failure
|
|
194
|
-
- ✅ Performance tracking
|
|
195
|
-
|
|
196
|
-
**Code highlights:**
|
|
197
|
-
```typescript
|
|
198
|
-
const job = new LuaJob({
|
|
199
|
-
name: "daily-cleanup",
|
|
200
|
-
|
|
201
|
-
schedule: {
|
|
202
|
-
type: 'cron',
|
|
203
|
-
expression: '0 2 * * *', // 2 AM daily
|
|
204
|
-
timezone: 'America/New_York'
|
|
205
|
-
},
|
|
206
|
-
|
|
207
|
-
timeout: 600, // 10 minutes
|
|
208
|
-
|
|
209
|
-
retry: {
|
|
210
|
-
maxAttempts: 3,
|
|
211
|
-
backoffSeconds: 60
|
|
212
|
-
},
|
|
213
|
-
|
|
214
|
-
execute: async () => {
|
|
215
|
-
// Clean old user events (90+ days)
|
|
216
|
-
const ninetyDaysAgo = new Date(Date.now() - 90 * 24 * 60 * 60 * 1000);
|
|
217
|
-
const oldEvents = await Data.get('user-events', {});
|
|
218
|
-
|
|
219
|
-
let deleted = 0;
|
|
220
|
-
for (const event of oldEvents) {
|
|
221
|
-
if (new Date(event.receivedAt) < ninetyDaysAgo) {
|
|
222
|
-
await Data.delete('user-events', event.id);
|
|
223
|
-
deleted++;
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
return { recordsDeleted: deleted };
|
|
228
|
-
}
|
|
229
|
-
});
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
**Cron expressions:**
|
|
233
|
-
```
|
|
234
|
-
'0 2 * * *' - Daily at 2 AM
|
|
235
|
-
'0 */6 * * *' - Every 6 hours
|
|
236
|
-
'0 0 * * 0' - Weekly on Sunday at midnight
|
|
237
|
-
'0 0 1 * *' - Monthly on 1st at midnight
|
|
238
|
-
'*/30 * * * *' - Every 30 minutes
|
|
239
|
-
```
|
|
240
|
-
|
|
241
|
-
---
|
|
242
|
-
|
|
243
|
-
### 2. Health Check Job
|
|
244
|
-
|
|
245
|
-
**File:** `src/jobs/HealthCheckJob.ts`
|
|
246
|
-
|
|
247
|
-
**What it does:** Runs every 5 minutes to monitor system health.
|
|
248
|
-
|
|
249
|
-
**Use cases:**
|
|
250
|
-
- API health monitoring
|
|
251
|
-
- Database connectivity checks
|
|
252
|
-
- Uptime tracking
|
|
253
|
-
- Performance monitoring
|
|
254
|
-
|
|
255
|
-
**Schedule:** Interval (every 5 minutes)
|
|
256
|
-
|
|
257
|
-
**Key features:**
|
|
258
|
-
- ✅ Interval-based scheduling
|
|
259
|
-
- ✅ Multiple service checks
|
|
260
|
-
- ✅ Health metric logging
|
|
261
|
-
- ✅ Alert on failures
|
|
262
|
-
|
|
263
|
-
**Code highlights:**
|
|
264
|
-
```typescript
|
|
265
|
-
const job = new LuaJob({
|
|
266
|
-
name: "health-check",
|
|
267
|
-
|
|
268
|
-
schedule: {
|
|
269
|
-
type: 'interval',
|
|
270
|
-
seconds: 300 // Every 5 minutes
|
|
271
|
-
},
|
|
272
|
-
|
|
273
|
-
timeout: 30,
|
|
274
|
-
|
|
275
|
-
execute: async () => {
|
|
276
|
-
const checks: any = {};
|
|
277
|
-
|
|
278
|
-
// Check database
|
|
279
|
-
try {
|
|
280
|
-
await Data.get('health-checks', {}, 1, 1);
|
|
281
|
-
checks.database = { status: 'healthy' };
|
|
282
|
-
} catch (error) {
|
|
283
|
-
checks.database = { status: 'unhealthy', error };
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
// Check Products API
|
|
287
|
-
try {
|
|
288
|
-
await Products.get(1, 1);
|
|
289
|
-
checks.productsApi = { status: 'healthy' };
|
|
290
|
-
} catch (error) {
|
|
291
|
-
checks.productsApi = { status: 'unhealthy', error };
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
const allHealthy = Object.values(checks)
|
|
295
|
-
.every((c: any) => c.status === 'healthy');
|
|
296
|
-
|
|
297
|
-
// Log health status
|
|
298
|
-
await Data.create('health-checks', {
|
|
299
|
-
status: allHealthy ? 'healthy' : 'degraded',
|
|
300
|
-
checks,
|
|
301
|
-
timestamp: new Date().toISOString()
|
|
302
|
-
});
|
|
303
|
-
|
|
304
|
-
return { status: allHealthy ? 'healthy' : 'degraded', checks };
|
|
305
|
-
}
|
|
306
|
-
});
|
|
307
|
-
```
|
|
308
|
-
|
|
309
|
-
---
|
|
310
|
-
|
|
311
|
-
### 3. Data Migration Job
|
|
312
|
-
|
|
313
|
-
**File:** `src/jobs/DataMigrationJob.ts`
|
|
314
|
-
|
|
315
|
-
**What it does:** One-time migration at a specific date/time.
|
|
316
|
-
|
|
317
|
-
**Use cases:**
|
|
318
|
-
- Schema migrations
|
|
319
|
-
- Data format updates
|
|
320
|
-
- One-time data processing
|
|
321
|
-
- Scheduled maintenance tasks
|
|
322
|
-
|
|
323
|
-
**Schedule:** Once (specific date/time)
|
|
324
|
-
|
|
325
|
-
**Key features:**
|
|
326
|
-
- ✅ One-time execution
|
|
327
|
-
- ✅ Batch processing
|
|
328
|
-
- ✅ Progress logging
|
|
329
|
-
- ✅ Migration reports
|
|
330
|
-
|
|
331
|
-
**Code highlights:**
|
|
332
|
-
```typescript
|
|
333
|
-
const job = new LuaJob({
|
|
334
|
-
name: "migrate-user-schema",
|
|
335
|
-
|
|
336
|
-
schedule: {
|
|
337
|
-
type: 'once',
|
|
338
|
-
executeAt: new Date('2025-12-31T02:00:00Z')
|
|
339
|
-
},
|
|
340
|
-
|
|
341
|
-
timeout: 1800, // 30 minutes for large migrations
|
|
342
|
-
|
|
343
|
-
retry: {
|
|
344
|
-
maxAttempts: 3,
|
|
345
|
-
backoffSeconds: 300
|
|
346
|
-
},
|
|
347
|
-
|
|
348
|
-
execute: async () => {
|
|
349
|
-
const oldEvents = await Data.get('user-events', {});
|
|
350
|
-
let migrated = 0;
|
|
351
|
-
|
|
352
|
-
for (const event of oldEvents) {
|
|
353
|
-
// Transform to new schema
|
|
354
|
-
const newEvent = {
|
|
355
|
-
eventId: event.id,
|
|
356
|
-
eventType: event.type || 'unknown',
|
|
357
|
-
userId: event.userId || event.user_id,
|
|
358
|
-
// ... transform other fields
|
|
359
|
-
};
|
|
360
|
-
|
|
361
|
-
await Data.create('user-events-v2', newEvent);
|
|
362
|
-
migrated++;
|
|
363
|
-
|
|
364
|
-
if (migrated % 100 === 0) {
|
|
365
|
-
console.log(`Migrated ${migrated} records...`);
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
return { migrated };
|
|
370
|
-
}
|
|
371
|
-
});
|
|
372
|
-
```
|
|
373
|
-
|
|
374
|
-
---
|
|
375
|
-
|
|
376
|
-
### 4. Abandoned Basket Processor Job
|
|
377
|
-
|
|
378
|
-
**File:** `src/jobs/AbandonedBasketProcessorJob.ts`
|
|
379
|
-
|
|
380
|
-
**What it does:** Processes basket checkout reminders created by tools.
|
|
381
|
-
|
|
382
|
-
**This is the companion job for SmartBasketTool!**
|
|
383
|
-
|
|
384
|
-
**Schedule:** Interval (every 15 minutes)
|
|
385
|
-
|
|
386
|
-
**Code highlights:**
|
|
387
|
-
```typescript
|
|
388
|
-
const job = new LuaJob({
|
|
389
|
-
name: "process-basket-reminders",
|
|
390
|
-
|
|
391
|
-
schedule: {
|
|
392
|
-
type: 'interval',
|
|
393
|
-
seconds: 900 // 15 minutes
|
|
394
|
-
},
|
|
395
|
-
|
|
396
|
-
execute: async () => {
|
|
397
|
-
// Get pending reminders
|
|
398
|
-
const reminders = await Data.get('basket-reminders', {});
|
|
399
|
-
const now = new Date();
|
|
400
|
-
|
|
401
|
-
for (const reminder of reminders) {
|
|
402
|
-
if (new Date(reminder.scheduledFor) > now) continue;
|
|
403
|
-
if (reminder.status !== 'pending') continue;
|
|
404
|
-
|
|
405
|
-
// Check basket status
|
|
406
|
-
const basket = await Baskets.getById(reminder.basketId);
|
|
407
|
-
|
|
408
|
-
if (basket.status === 'active') {
|
|
409
|
-
// Abandoned! Send reminder
|
|
410
|
-
await Data.create('abandoned-baskets', {
|
|
411
|
-
basketId: basket.id,
|
|
412
|
-
abandonedAt: new Date().toISOString()
|
|
413
|
-
});
|
|
414
|
-
|
|
415
|
-
// TODO: Send email/SMS reminder
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
// Mark as processed
|
|
419
|
-
await Data.update('basket-reminders', reminder.id, {
|
|
420
|
-
status: 'completed'
|
|
421
|
-
});
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
return { success: true };
|
|
425
|
-
}
|
|
426
|
-
});
|
|
427
|
-
```
|
|
428
|
-
|
|
429
|
-
---
|
|
430
|
-
|
|
431
|
-
## Dynamic Job Creation
|
|
432
|
-
|
|
433
|
-
### Smart Basket Tool
|
|
434
|
-
|
|
435
|
-
**File:** `src/tools/SmartBasketTool.ts`
|
|
436
|
-
|
|
437
|
-
**What it does:** Creates a basket AND schedules a reminder to check for abandonment.
|
|
438
|
-
|
|
439
|
-
**This demonstrates creating jobs from within tools!**
|
|
440
|
-
|
|
441
|
-
**The Flow:**
|
|
442
|
-
```
|
|
443
|
-
User: "Create a basket"
|
|
444
|
-
↓
|
|
445
|
-
Tool: Creates basket
|
|
446
|
-
↓
|
|
447
|
-
Tool: Schedules reminder (3 hours later)
|
|
448
|
-
↓
|
|
449
|
-
Job: Checks if basket was checked out
|
|
450
|
-
↓
|
|
451
|
-
If abandoned → Send reminder email
|
|
452
|
-
```
|
|
453
|
-
|
|
454
|
-
**Code highlights:**
|
|
455
|
-
```typescript
|
|
456
|
-
export class CreateSmartBasketTool implements LuaTool {
|
|
457
|
-
name = "create_smart_basket";
|
|
458
|
-
description = "Creates basket with auto-reminder";
|
|
459
|
-
|
|
460
|
-
async execute(input: { currency: string }) {
|
|
461
|
-
// 1. Create basket
|
|
462
|
-
const basket = await Baskets.create({
|
|
463
|
-
currency: input.currency
|
|
464
|
-
});
|
|
465
|
-
|
|
466
|
-
// 2. Schedule reminder for 3 hours later
|
|
467
|
-
const checkTime = new Date(Date.now() + 3 * 60 * 60 * 1000);
|
|
468
|
-
|
|
469
|
-
await Data.create('basket-reminders', {
|
|
470
|
-
type: 'basket-checkout-reminder',
|
|
471
|
-
basketId: basket.id,
|
|
472
|
-
scheduledFor: checkTime.toISOString(),
|
|
473
|
-
status: 'pending'
|
|
474
|
-
});
|
|
475
|
-
|
|
476
|
-
return {
|
|
477
|
-
basket,
|
|
478
|
-
reminder: {
|
|
479
|
-
scheduledFor: checkTime.toISOString()
|
|
480
|
-
}
|
|
481
|
-
};
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
```
|
|
485
|
-
|
|
486
|
-
**How it works:**
|
|
487
|
-
|
|
488
|
-
1. **Tool creates basket** → Returns basket ID to user
|
|
489
|
-
2. **Tool creates reminder** → Stores in custom data with future timestamp
|
|
490
|
-
3. **Recurring job runs** → Every 15 minutes, checks for due reminders
|
|
491
|
-
4. **Job processes reminder** → Checks if basket is still active
|
|
492
|
-
5. **If abandoned** → Sends reminder email/notification
|
|
493
|
-
|
|
494
|
-
**Companion tool:**
|
|
495
|
-
```typescript
|
|
496
|
-
export class CheckAbandonedBasketsTool implements LuaTool {
|
|
497
|
-
name = "check_abandoned_baskets";
|
|
498
|
-
|
|
499
|
-
async execute(input: { basketId?: string }) {
|
|
500
|
-
const reminders = await Data.get('basket-reminders', {});
|
|
501
|
-
|
|
502
|
-
for (const reminder of reminders) {
|
|
503
|
-
const basket = await Baskets.getById(reminder.basketId);
|
|
504
|
-
|
|
505
|
-
if (basket.status === 'active') {
|
|
506
|
-
// Abandoned!
|
|
507
|
-
await Data.create('abandoned-baskets', {
|
|
508
|
-
basketId: basket.id,
|
|
509
|
-
abandonedAt: new Date().toISOString()
|
|
510
|
-
});
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
return { success: true };
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
|
-
```
|
|
518
|
-
|
|
519
|
-
---
|
|
520
|
-
|
|
521
|
-
## Complete Integration Example
|
|
522
|
-
|
|
523
|
-
Here's how to use all these features together in your `src/index.ts`:
|
|
524
|
-
|
|
525
|
-
```typescript
|
|
526
|
-
import { LuaSkill } from "lua-cli";
|
|
527
|
-
|
|
528
|
-
// Import webhooks
|
|
529
|
-
import userEventWebhook from "./webhooks/UserEventWebhook";
|
|
530
|
-
import paymentWebhook from "./webhooks/PaymentWebhook";
|
|
531
|
-
|
|
532
|
-
// Import jobs
|
|
533
|
-
import dailyCleanupJob from "./jobs/DailyCleanupJob";
|
|
534
|
-
import healthCheckJob from "./jobs/HealthCheckJob";
|
|
535
|
-
import dataMigrationJob from "./jobs/DataMigrationJob";
|
|
536
|
-
import abandonedBasketProcessorJob from "./jobs/AbandonedBasketProcessorJob";
|
|
537
|
-
|
|
538
|
-
// Import tools
|
|
539
|
-
import { CreateSmartBasketTool, CheckAbandonedBasketsTool } from "./tools/SmartBasketTool";
|
|
540
|
-
|
|
541
|
-
// Create skill with tools
|
|
542
|
-
const basketSkill = new LuaSkill({
|
|
543
|
-
name: "basket-skill",
|
|
544
|
-
version: "1.0.0",
|
|
545
|
-
description: "Smart basket management with abandoned cart recovery",
|
|
546
|
-
context: "This skill manages shopping baskets and automatically sends reminders for abandoned carts.",
|
|
547
|
-
tools: [
|
|
548
|
-
new CreateSmartBasketTool(),
|
|
549
|
-
new CheckAbandonedBasketsTool()
|
|
550
|
-
]
|
|
551
|
-
});
|
|
552
|
-
|
|
553
|
-
// Note: Webhooks and Jobs are standalone, not added to skills
|
|
554
|
-
// They are detected automatically during compilation
|
|
555
|
-
```
|
|
556
|
-
|
|
557
|
-
---
|
|
558
|
-
|
|
559
|
-
## Testing Examples
|
|
560
|
-
|
|
561
|
-
### Test Webhook
|
|
562
|
-
```bash
|
|
563
|
-
lua test webhook
|
|
564
|
-
|
|
565
|
-
# You'll be prompted for:
|
|
566
|
-
# - Query params: {"source": "mobile"}
|
|
567
|
-
# - Headers: {"x-api-key": "test-key"}
|
|
568
|
-
# - Body: {"eventType": "signup", "userId": "123", "email": "test@example.com"}
|
|
569
|
-
|
|
570
|
-
# Output: Webhook executes and returns result
|
|
571
|
-
```
|
|
572
|
-
|
|
573
|
-
### Test Job
|
|
574
|
-
```bash
|
|
575
|
-
lua test job
|
|
576
|
-
|
|
577
|
-
# Select job to test
|
|
578
|
-
# Job executes immediately (ignores schedule)
|
|
579
|
-
# See result
|
|
580
|
-
```
|
|
581
|
-
|
|
582
|
-
### Test Tool
|
|
583
|
-
```bash
|
|
584
|
-
lua test skill
|
|
585
|
-
|
|
586
|
-
# Select: create_smart_basket
|
|
587
|
-
# Enter: currency: USD
|
|
588
|
-
# Tool creates basket AND schedules reminder!
|
|
589
|
-
```
|
|
590
|
-
|
|
591
|
-
---
|
|
592
|
-
|
|
593
|
-
## Deployment Workflow
|
|
594
|
-
|
|
595
|
-
```bash
|
|
596
|
-
# 1. Compile everything
|
|
597
|
-
lua compile
|
|
598
|
-
# ✅ Detects: tools, webhooks, jobs
|
|
599
|
-
# ✅ Creates webhook/job IDs on backend
|
|
600
|
-
# ✅ Updates lua.skill.yaml
|
|
601
|
-
|
|
602
|
-
# 2. Test locally
|
|
603
|
-
lua test skill
|
|
604
|
-
lua test webhook
|
|
605
|
-
lua test job
|
|
606
|
-
|
|
607
|
-
# 3. Push to server
|
|
608
|
-
lua push skill
|
|
609
|
-
lua push webhook
|
|
610
|
-
lua push job
|
|
611
|
-
|
|
612
|
-
# 4. Deploy to production
|
|
613
|
-
lua skills production # Deploy skill
|
|
614
|
-
lua webhooks production # Deploy webhook
|
|
615
|
-
lua jobs production # Deploy and activate job
|
|
616
|
-
```
|
|
617
|
-
|
|
618
|
-
---
|
|
619
|
-
|
|
620
|
-
## Advanced Patterns
|
|
621
|
-
|
|
622
|
-
### Pattern 1: Webhook → Data → Job
|
|
623
|
-
|
|
624
|
-
**Flow:** Webhook receives data → Stores in DB → Job processes later
|
|
625
|
-
|
|
626
|
-
```typescript
|
|
627
|
-
// Webhook: Receive order
|
|
628
|
-
const orderWebhook = new LuaWebhook({
|
|
629
|
-
execute: async ({ body }) => {
|
|
630
|
-
await Data.create('pending-orders', body);
|
|
631
|
-
return { queued: true };
|
|
632
|
-
}
|
|
633
|
-
});
|
|
634
|
-
|
|
635
|
-
// Job: Process orders every hour
|
|
636
|
-
const processOrdersJob = new LuaJob({
|
|
637
|
-
schedule: { type: 'interval', seconds: 3600 },
|
|
638
|
-
execute: async () => {
|
|
639
|
-
const pending = await Data.get('pending-orders', {});
|
|
640
|
-
for (const order of pending) {
|
|
641
|
-
// Process order
|
|
642
|
-
await Orders.create(order);
|
|
643
|
-
await Data.delete('pending-orders', order.id);
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
});
|
|
647
|
-
```
|
|
648
|
-
|
|
649
|
-
---
|
|
650
|
-
|
|
651
|
-
### Pattern 2: Tool → Job → Webhook
|
|
652
|
-
|
|
653
|
-
**Flow:** Tool triggers job → Job processes → Webhook notifies external system
|
|
654
|
-
|
|
655
|
-
```typescript
|
|
656
|
-
// Tool: Start export
|
|
657
|
-
class ExportDataTool implements LuaTool {
|
|
658
|
-
async execute(input: any) {
|
|
659
|
-
// Trigger export job
|
|
660
|
-
await Jobs.trigger('job_export_data');
|
|
661
|
-
return { started: true };
|
|
662
|
-
}
|
|
663
|
-
}
|
|
664
|
-
|
|
665
|
-
// Job: Export data
|
|
666
|
-
const exportJob = new LuaJob({
|
|
667
|
-
execute: async () => {
|
|
668
|
-
const data = await Data.get('users', {});
|
|
669
|
-
// Export logic...
|
|
670
|
-
|
|
671
|
-
// Notify webhook when done
|
|
672
|
-
// (Webhook would be configured to notify admin)
|
|
673
|
-
return { exported: data.length };
|
|
674
|
-
}
|
|
675
|
-
});
|
|
676
|
-
```
|
|
677
|
-
|
|
678
|
-
---
|
|
679
|
-
|
|
680
|
-
### Pattern 3: Scheduled Job Creates Dynamic Jobs
|
|
681
|
-
|
|
682
|
-
**Flow:** Recurring job → Checks conditions → Creates one-time jobs as needed
|
|
683
|
-
|
|
684
|
-
```typescript
|
|
685
|
-
const monitorJob = new LuaJob({
|
|
686
|
-
name: "monitor-and-schedule",
|
|
687
|
-
schedule: { type: 'cron', expression: '0 * * * *' }, // Hourly
|
|
688
|
-
|
|
689
|
-
execute: async () => {
|
|
690
|
-
const orders = await Orders.get();
|
|
691
|
-
|
|
692
|
-
for (const order of orders) {
|
|
693
|
-
if (order.status === 'pending' && needsFollowUp(order)) {
|
|
694
|
-
// Schedule a one-time follow-up job
|
|
695
|
-
await Data.create('follow-up-jobs', {
|
|
696
|
-
orderId: order.id,
|
|
697
|
-
scheduledFor: new Date(Date.now() + 24 * 60 * 60 * 1000),
|
|
698
|
-
type: 'order-follow-up'
|
|
699
|
-
});
|
|
700
|
-
}
|
|
701
|
-
}
|
|
702
|
-
}
|
|
703
|
-
});
|
|
704
|
-
```
|
|
705
|
-
|
|
706
|
-
---
|
|
707
|
-
|
|
708
|
-
## 🎯 Recommended Usage
|
|
709
|
-
|
|
710
|
-
### When to Use Webhooks
|
|
711
|
-
- ✅ Receiving data from external systems
|
|
712
|
-
- ✅ Real-time event processing
|
|
713
|
-
- ✅ Third-party integrations (Stripe, Zapier, etc.)
|
|
714
|
-
- ✅ API callbacks
|
|
715
|
-
|
|
716
|
-
### When to Use Jobs
|
|
717
|
-
- ✅ Scheduled maintenance (cleanup, backups)
|
|
718
|
-
- ✅ Recurring reports (daily/weekly reports)
|
|
719
|
-
- ✅ Batch processing (process queued items)
|
|
720
|
-
- ✅ Monitoring and health checks
|
|
721
|
-
- ✅ One-time migrations
|
|
722
|
-
|
|
723
|
-
### When to Create Jobs from Tools
|
|
724
|
-
- ✅ User-initiated scheduled actions
|
|
725
|
-
- ✅ Delayed follow-ups (abandoned cart, renewal reminders)
|
|
726
|
-
- ✅ Conditional future actions
|
|
727
|
-
- ✅ Dynamic scheduling based on business logic
|
|
728
|
-
|
|
729
|
-
---
|
|
730
|
-
|
|
731
|
-
## 📚 Learning Path
|
|
732
|
-
|
|
733
|
-
### Beginner
|
|
734
|
-
1. ✅ Read UserEventWebhook.ts (simple webhook)
|
|
735
|
-
2. ✅ Read HealthCheckJob.ts (simple job)
|
|
736
|
-
3. ✅ Test them locally
|
|
737
|
-
|
|
738
|
-
### Intermediate
|
|
739
|
-
4. ✅ Read PaymentWebhook.ts (real-world webhook)
|
|
740
|
-
5. ✅ Read DailyCleanupJob.ts (practical cron job)
|
|
741
|
-
6. ✅ Modify and deploy
|
|
742
|
-
|
|
743
|
-
### Advanced
|
|
744
|
-
7. ✅ Read SmartBasketTool.ts (dynamic job creation)
|
|
745
|
-
8. ✅ Read AbandonedBasketProcessorJob.ts (companion job)
|
|
746
|
-
9. ✅ Build your own integrated system
|
|
747
|
-
|
|
748
|
-
---
|
|
749
|
-
|
|
750
|
-
## 🚀 Quick Start
|
|
751
|
-
|
|
752
|
-
### 1. Enable the examples
|
|
753
|
-
```typescript
|
|
754
|
-
// In src/index.ts
|
|
755
|
-
import userEventWebhook from "./webhooks/UserEventWebhook";
|
|
756
|
-
import dailyCleanupJob from "./jobs/DailyCleanupJob";
|
|
757
|
-
|
|
758
|
-
// They're automatically detected during compilation!
|
|
759
|
-
```
|
|
760
|
-
|
|
761
|
-
### 2. Compile
|
|
762
|
-
```bash
|
|
763
|
-
lua compile
|
|
764
|
-
# ✅ Found 1 webhook(s), 1 job(s)
|
|
765
|
-
```
|
|
766
|
-
|
|
767
|
-
### 3. Test
|
|
768
|
-
```bash
|
|
769
|
-
lua test webhook
|
|
770
|
-
lua test job
|
|
771
|
-
```
|
|
772
|
-
|
|
773
|
-
### 4. Deploy
|
|
774
|
-
```bash
|
|
775
|
-
lua push webhook
|
|
776
|
-
lua push job
|
|
777
|
-
lua webhooks production # Activate
|
|
778
|
-
lua jobs production # Activate and start scheduling
|
|
779
|
-
```
|
|
780
|
-
|
|
781
|
-
---
|
|
782
|
-
|
|
783
|
-
## 💡 Tips
|
|
784
|
-
|
|
785
|
-
### Webhooks
|
|
786
|
-
- Always validate input with schemas
|
|
787
|
-
- Use API keys for security
|
|
788
|
-
- Keep execution under 30 seconds
|
|
789
|
-
- Return structured responses
|
|
790
|
-
- Log important events
|
|
791
|
-
|
|
792
|
-
### Jobs
|
|
793
|
-
- Use appropriate schedule type (cron/interval/once)
|
|
794
|
-
- Set reasonable timeouts
|
|
795
|
-
- Configure retries for critical jobs
|
|
796
|
-
- Log execution results
|
|
797
|
-
- Monitor execution history
|
|
798
|
-
|
|
799
|
-
### Dynamic Jobs from Tools
|
|
800
|
-
- Store job configuration in custom data
|
|
801
|
-
- Use a recurring job to process scheduled items
|
|
802
|
-
- Include enough context to execute the job later
|
|
803
|
-
- Clean up processed job records
|
|
804
|
-
|
|
805
|
-
---
|
|
806
|
-
|
|
807
|
-
## 📖 Related Documentation
|
|
808
|
-
|
|
809
|
-
- **[WEBHOOK_API_SPEC.md](../WEBHOOK_API_SPEC.md)** - Complete webhook API reference
|
|
810
|
-
- **[JOB_API_SPEC.md](../JOB_API_SPEC.md)** - Complete job API reference
|
|
811
|
-
- **[WEBHOOKS_JOBS_USAGE_GUIDE.md](../WEBHOOKS_JOBS_USAGE_GUIDE.md)** - Detailed usage guide
|
|
812
|
-
- **[TOOL_EXAMPLES.md](./TOOL_EXAMPLES.md)** - Tool examples
|
|
813
|
-
|
|
814
|
-
---
|
|
815
|
-
|
|
816
|
-
**Ready to build powerful integrations with webhooks and scheduled jobs!** 🚀
|
|
817
|
-
|