lua-cli 2.5.7 → 3.0.0-alpha.1
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/agent.api.service.d.ts +45 -0
- package/dist/api/agent.api.service.js +54 -0
- package/dist/api/job.api.service.d.ts +210 -0
- package/dist/api/job.api.service.js +200 -0
- package/dist/api/lazy-instances.d.ts +24 -0
- package/dist/api/lazy-instances.js +48 -0
- package/dist/api/postprocessor.api.service.d.ts +98 -0
- package/dist/api/postprocessor.api.service.js +76 -0
- package/dist/api/preprocessor.api.service.d.ts +98 -0
- package/dist/api/preprocessor.api.service.js +76 -0
- package/dist/api/user.data.api.service.d.ts +28 -0
- package/dist/api/user.data.api.service.js +51 -0
- package/dist/api/webhook.api.service.d.ts +151 -0
- package/dist/api/webhook.api.service.js +134 -0
- package/dist/api-exports.d.ts +156 -41
- package/dist/api-exports.js +182 -21
- package/dist/cli/command-definitions.js +149 -7
- package/dist/commands/compile.js +124 -5
- package/dist/commands/completion.d.ts +11 -0
- package/dist/commands/completion.js +209 -0
- package/dist/commands/env.d.ts +3 -2
- package/dist/commands/env.js +42 -17
- package/dist/commands/features.d.ts +16 -0
- package/dist/commands/features.js +352 -0
- package/dist/commands/index.d.ts +7 -0
- package/dist/commands/index.js +7 -0
- package/dist/commands/init.js +53 -7
- package/dist/commands/jobs.d.ts +20 -0
- package/dist/commands/jobs.js +533 -0
- package/dist/commands/logs.js +2 -5
- package/dist/commands/persona.d.ts +3 -2
- package/dist/commands/persona.js +43 -18
- package/dist/commands/postprocessors.d.ts +8 -0
- package/dist/commands/postprocessors.js +431 -0
- package/dist/commands/preprocessors.d.ts +8 -0
- package/dist/commands/preprocessors.js +431 -0
- package/dist/commands/push.d.ts +9 -13
- package/dist/commands/push.js +937 -69
- package/dist/commands/skills.d.ts +16 -0
- package/dist/commands/skills.js +438 -0
- package/dist/commands/test.d.ts +9 -18
- package/dist/commands/test.js +558 -82
- package/dist/commands/webhooks.d.ts +18 -0
- package/dist/commands/webhooks.js +424 -0
- package/dist/common/data.entry.instance.d.ts +7 -0
- package/dist/common/data.entry.instance.js +15 -0
- package/dist/common/job.instance.d.ts +77 -0
- package/dist/common/job.instance.js +108 -0
- package/dist/common/order.instance.d.ts +6 -0
- package/dist/common/order.instance.js +14 -0
- package/dist/common/product.instance.d.ts +6 -0
- package/dist/common/product.instance.js +14 -0
- package/dist/common/user.instance.d.ts +15 -0
- package/dist/common/user.instance.js +38 -0
- package/dist/config/constants.d.ts +2 -2
- package/dist/config/constants.js +4 -4
- package/dist/index.js +14 -3
- package/dist/interfaces/agent.d.ts +33 -1
- package/dist/interfaces/chat.d.ts +22 -0
- package/dist/interfaces/index.d.ts +10 -0
- package/dist/interfaces/index.js +7 -0
- package/dist/interfaces/jobs.d.ts +172 -0
- package/dist/interfaces/jobs.js +5 -0
- package/dist/interfaces/message.d.ts +18 -0
- package/dist/interfaces/message.js +1 -0
- package/dist/interfaces/postprocessors.d.ts +35 -0
- package/dist/interfaces/postprocessors.js +4 -0
- package/dist/interfaces/preprocessors.d.ts +35 -0
- package/dist/interfaces/preprocessors.js +4 -0
- package/dist/interfaces/webhooks.d.ts +104 -0
- package/dist/interfaces/webhooks.js +5 -0
- package/dist/types/api-contracts.d.ts +14 -0
- package/dist/types/api-contracts.js +0 -7
- package/dist/types/compile.types.d.ts +49 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.js +1 -1
- package/dist/types/skill.d.ts +502 -0
- package/dist/types/skill.js +477 -0
- package/dist/utils/agent-management.d.ts +25 -0
- package/dist/utils/agent-management.js +67 -0
- package/dist/utils/bundling.d.ts +31 -1
- package/dist/utils/bundling.js +653 -10
- package/dist/utils/compile.d.ts +63 -0
- package/dist/utils/compile.js +691 -36
- package/dist/utils/deployment.d.ts +2 -1
- package/dist/utils/deployment.js +16 -2
- package/dist/utils/init-agent.d.ts +3 -1
- package/dist/utils/init-agent.js +6 -4
- package/dist/utils/init-prompts.d.ts +2 -1
- package/dist/utils/init-prompts.js +14 -9
- package/dist/utils/job-management.d.ts +24 -0
- package/dist/utils/job-management.js +264 -0
- package/dist/utils/postprocessor-management.d.ts +9 -0
- package/dist/utils/postprocessor-management.js +118 -0
- package/dist/utils/preprocessor-management.d.ts +9 -0
- package/dist/utils/preprocessor-management.js +118 -0
- package/dist/utils/sandbox.d.ts +61 -1
- package/dist/utils/sandbox.js +283 -72
- package/dist/utils/tool-detection.d.ts +3 -2
- package/dist/utils/tool-detection.js +18 -4
- package/dist/utils/webhook-management.d.ts +24 -0
- package/dist/utils/webhook-management.js +256 -0
- package/dist/web/app.css +152 -736
- package/dist/web/app.js +45 -45
- package/package.json +2 -2
- package/template/AGENT_CONFIGURATION.md +251 -0
- package/template/COMPLEX_JOB_EXAMPLES.md +795 -0
- package/template/DYNAMIC_JOB_CREATION.md +371 -0
- package/template/README.md +30 -2
- package/template/WEBHOOKS_JOBS_QUICKSTART.md +318 -0
- package/template/WEBHOOK_JOB_EXAMPLES.md +817 -0
- package/template/package.json +1 -1
- package/template/src/index-agent-example.ts +201 -0
- package/template/src/index.ts +39 -0
- package/template/src/jobs/AbandonedBasketProcessorJob.ts +139 -0
- package/template/src/jobs/DailyCleanupJob.ts +100 -0
- package/template/src/jobs/DataMigrationJob.ts +133 -0
- package/template/src/jobs/HealthCheckJob.ts +87 -0
- package/template/src/postprocessors/ResponseFormatter.ts +151 -0
- package/template/src/preprocessors/MessageFilter.ts +91 -0
- package/template/src/tools/GameScoreTrackerTool.ts +356 -0
- package/template/src/tools/SmartBasketTool.ts +188 -0
- package/template/src/webhooks/PaymentWebhook.ts +113 -0
- package/template/src/webhooks/UserEventWebhook.ts +77 -0
package/template/package.json
CHANGED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
// /**
|
|
2
|
+
// * LuaAgent Example - Simplified Agent Configuration
|
|
3
|
+
// *
|
|
4
|
+
// * This example shows the NEW, RECOMMENDED way to define your agent using LuaAgent.
|
|
5
|
+
// * Instead of exporting individual skills, webhooks, jobs, and processors,
|
|
6
|
+
// * you create one unified LuaAgent object that contains everything.
|
|
7
|
+
// *
|
|
8
|
+
// * Benefits:
|
|
9
|
+
// * - Simpler, cleaner code
|
|
10
|
+
// * - All configuration in one place
|
|
11
|
+
// * - Easier to understand and maintain
|
|
12
|
+
// * - Agent persona is synced with lua.skill.yaml automatically
|
|
13
|
+
// */
|
|
14
|
+
|
|
15
|
+
// import { LuaAgent, LuaSkill } from "lua-cli";
|
|
16
|
+
// import GetWeatherTool from "./tools/GetWeatherTool";
|
|
17
|
+
// import { GetUserDataTool, UpdateUserDataTool } from "./tools/UserDataTool";
|
|
18
|
+
// import CreatePostTool from "./tools/CreatePostTool";
|
|
19
|
+
// import { SearchProductsTool, CreateProductTool, UpdateProductTool, GetAllProductsTool, GetProductByIdTool, DeleteProductTool } from "./tools/ProductsTool";
|
|
20
|
+
// import { CreateBasketTool, GetBasketsTool, AddItemToBasketTool, RemoveItemFromBasketTool, ClearBasketTool, UpdateBasketStatusTool, UpdateBasketMetadataTool, CheckoutBasketTool, GetBasketByIdTool } from "./tools/BasketTool";
|
|
21
|
+
// import { CreateOrderTool, UpdateOrderStatusTool, GetOrderByIdTool, GetUserOrdersTool } from "./tools/OrderTool";
|
|
22
|
+
// import { CreateMovieTool, GetMoviesTool, GetMovieByIdTool, UpdateMovieTool, SearchMoviesTool, DeleteMovieTool } from "./tools/CustomDataTool";
|
|
23
|
+
|
|
24
|
+
// // ============================================================================
|
|
25
|
+
// // WEBHOOK EXAMPLES (Uncomment to enable)
|
|
26
|
+
// // ============================================================================
|
|
27
|
+
// // import userEventWebhook from "./webhooks/UserEventWebhook";
|
|
28
|
+
// // import paymentWebhook from "./webhooks/PaymentWebhook";
|
|
29
|
+
|
|
30
|
+
// // ============================================================================
|
|
31
|
+
// // JOB EXAMPLES (Uncomment to enable)
|
|
32
|
+
// // ============================================================================
|
|
33
|
+
// // import dailyCleanupJob from "./jobs/DailyCleanupJob";
|
|
34
|
+
// // import healthCheckJob from "./jobs/HealthCheckJob";
|
|
35
|
+
|
|
36
|
+
// // ============================================================================
|
|
37
|
+
// // PREPROCESSOR/POSTPROCESSOR EXAMPLES
|
|
38
|
+
// // ============================================================================
|
|
39
|
+
// import messageFilter from "./preprocessors/MessageFilter";
|
|
40
|
+
// import responseFormatter from "./postprocessors/ResponseFormatter";
|
|
41
|
+
|
|
42
|
+
// // ============================================================================
|
|
43
|
+
// // SKILLS
|
|
44
|
+
// // ============================================================================
|
|
45
|
+
|
|
46
|
+
// // Skills can be defined separately for better organization
|
|
47
|
+
// const generalSkill = new LuaSkill({
|
|
48
|
+
// name: "general-skill",
|
|
49
|
+
// version: "1.0.0",
|
|
50
|
+
// description: "General utilities including weather and post creation",
|
|
51
|
+
// context: "This skill provides weather information and post creation capabilities.",
|
|
52
|
+
// tools: [
|
|
53
|
+
// new GetWeatherTool(),
|
|
54
|
+
// new CreatePostTool()
|
|
55
|
+
// ]
|
|
56
|
+
// });
|
|
57
|
+
|
|
58
|
+
// const userDataSkill = new LuaSkill({
|
|
59
|
+
// name: "user-data-skill",
|
|
60
|
+
// version: "1.0.0",
|
|
61
|
+
// description: "User data management",
|
|
62
|
+
// context: "This skill provides user data retrieval and update capabilities.",
|
|
63
|
+
// tools: [
|
|
64
|
+
// new GetUserDataTool(),
|
|
65
|
+
// new UpdateUserDataTool()
|
|
66
|
+
// ]
|
|
67
|
+
// });
|
|
68
|
+
|
|
69
|
+
// const productSkill = new LuaSkill({
|
|
70
|
+
// name: "product-skill",
|
|
71
|
+
// version: "1.0.0",
|
|
72
|
+
// description: "Product catalog management",
|
|
73
|
+
// context: "This skill provides comprehensive product management capabilities.",
|
|
74
|
+
// tools: [
|
|
75
|
+
// new SearchProductsTool(),
|
|
76
|
+
// new GetAllProductsTool(),
|
|
77
|
+
// new CreateProductTool(),
|
|
78
|
+
// new UpdateProductTool(),
|
|
79
|
+
// new GetProductByIdTool(),
|
|
80
|
+
// new DeleteProductTool()
|
|
81
|
+
// ]
|
|
82
|
+
// });
|
|
83
|
+
|
|
84
|
+
// const basketSkill = new LuaSkill({
|
|
85
|
+
// name: "basket-skill",
|
|
86
|
+
// version: "1.0.0",
|
|
87
|
+
// description: "Shopping basket management",
|
|
88
|
+
// context: "This skill provides shopping basket operations.",
|
|
89
|
+
// tools: [
|
|
90
|
+
// new CreateBasketTool(),
|
|
91
|
+
// new GetBasketsTool(),
|
|
92
|
+
// new AddItemToBasketTool(),
|
|
93
|
+
// new RemoveItemFromBasketTool(),
|
|
94
|
+
// new ClearBasketTool(),
|
|
95
|
+
// new UpdateBasketStatusTool(),
|
|
96
|
+
// new UpdateBasketMetadataTool(),
|
|
97
|
+
// new CheckoutBasketTool(),
|
|
98
|
+
// new GetBasketByIdTool()
|
|
99
|
+
// ]
|
|
100
|
+
// });
|
|
101
|
+
|
|
102
|
+
// const orderSkill = new LuaSkill({
|
|
103
|
+
// name: "order-skill",
|
|
104
|
+
// version: "1.0.0",
|
|
105
|
+
// description: "Order management",
|
|
106
|
+
// context: "This skill provides order management capabilities.",
|
|
107
|
+
// tools: [
|
|
108
|
+
// new CreateOrderTool(),
|
|
109
|
+
// new UpdateOrderStatusTool(),
|
|
110
|
+
// new GetOrderByIdTool(),
|
|
111
|
+
// new GetUserOrdersTool()
|
|
112
|
+
// ]
|
|
113
|
+
// });
|
|
114
|
+
|
|
115
|
+
// const customDataSkill = new LuaSkill({
|
|
116
|
+
// name: "custom-data-skill",
|
|
117
|
+
// version: "1.0.0",
|
|
118
|
+
// description: "Custom data management for movies",
|
|
119
|
+
// context: "This skill provides custom data storage and retrieval for movies.",
|
|
120
|
+
// tools: [
|
|
121
|
+
// new CreateMovieTool(),
|
|
122
|
+
// new GetMoviesTool(),
|
|
123
|
+
// new GetMovieByIdTool(),
|
|
124
|
+
// new UpdateMovieTool(),
|
|
125
|
+
// new SearchMoviesTool(),
|
|
126
|
+
// new DeleteMovieTool()
|
|
127
|
+
// ]
|
|
128
|
+
// });
|
|
129
|
+
|
|
130
|
+
// // ============================================================================
|
|
131
|
+
// // AGENT CONFIGURATION (NEW APPROACH)
|
|
132
|
+
// // ============================================================================
|
|
133
|
+
|
|
134
|
+
// /**
|
|
135
|
+
// * This is the main agent configuration.
|
|
136
|
+
// * The LuaAgent consolidates everything in one place:
|
|
137
|
+
// * - Agent persona (behavior and personality)
|
|
138
|
+
// * - Skills (collections of tools)
|
|
139
|
+
// * - Webhooks (HTTP endpoints)
|
|
140
|
+
// * - Jobs (scheduled tasks)
|
|
141
|
+
// * - PreProcessors (run before messages reach agent)
|
|
142
|
+
// * - PostProcessors (run after agent generates responses)
|
|
143
|
+
// *
|
|
144
|
+
// * The compiler will:
|
|
145
|
+
// * 1. Detect this LuaAgent
|
|
146
|
+
// * 2. Extract all components (skills, webhooks, jobs, processors)
|
|
147
|
+
// * 3. Sync the persona with lua.skill.yaml
|
|
148
|
+
// * 4. Deploy everything to the Lua platform
|
|
149
|
+
// */
|
|
150
|
+
// export const agent = new LuaAgent({
|
|
151
|
+
// name: "my-assistant",
|
|
152
|
+
// persona: `You are a helpful e-commerce assistant that can help users with:
|
|
153
|
+
// - Weather information
|
|
154
|
+
// - User account management
|
|
155
|
+
// - Product browsing and search
|
|
156
|
+
// - Shopping basket operations
|
|
157
|
+
// - Order management
|
|
158
|
+
// - Movie database management
|
|
159
|
+
|
|
160
|
+
// You are friendly, helpful, and provide clear responses. When users ask about products,
|
|
161
|
+
// help them search and find what they need. When they want to purchase, guide them through
|
|
162
|
+
// the basket and checkout process.`,
|
|
163
|
+
|
|
164
|
+
// welcomeMessage: "Hello! I'm your e-commerce assistant. I can help you find products, manage your basket, and track orders. How can I help you today?",
|
|
165
|
+
|
|
166
|
+
// // Add all your skills here
|
|
167
|
+
// skills: [
|
|
168
|
+
// generalSkill,
|
|
169
|
+
// userDataSkill,
|
|
170
|
+
// productSkill,
|
|
171
|
+
// basketSkill,
|
|
172
|
+
// orderSkill,
|
|
173
|
+
// customDataSkill
|
|
174
|
+
// ],
|
|
175
|
+
|
|
176
|
+
// // Uncomment to add webhooks
|
|
177
|
+
// // webhooks: [
|
|
178
|
+
// // userEventWebhook,
|
|
179
|
+
// // paymentWebhook
|
|
180
|
+
// // ],
|
|
181
|
+
|
|
182
|
+
// // Uncomment to add scheduled jobs
|
|
183
|
+
// // jobs: [
|
|
184
|
+
// // dailyCleanupJob,
|
|
185
|
+
// // healthCheckJob
|
|
186
|
+
// // ],
|
|
187
|
+
|
|
188
|
+
// // Message preprocessors (filter spam, add context, etc.)
|
|
189
|
+
// preProcessors: [
|
|
190
|
+
// messageFilter
|
|
191
|
+
// ],
|
|
192
|
+
|
|
193
|
+
// // Response postprocessors (format output, add branding, etc.)
|
|
194
|
+
// postProcessors: [
|
|
195
|
+
// responseFormatter
|
|
196
|
+
// ]
|
|
197
|
+
// });
|
|
198
|
+
|
|
199
|
+
// // That's it! The compiler will detect this LuaAgent and deploy everything.
|
|
200
|
+
// // No need to export individual skills, webhooks, jobs, etc.
|
|
201
|
+
|
package/template/src/index.ts
CHANGED
|
@@ -8,6 +8,45 @@ import { CreateBasketTool, GetBasketsTool, AddItemToBasketTool, RemoveItemFromBa
|
|
|
8
8
|
import { CreateOrderTool, UpdateOrderStatusTool, GetOrderByIdTool, GetUserOrdersTool } from "./tools/OrderTool";
|
|
9
9
|
import { CreateMovieTool, GetMoviesTool, GetMovieByIdTool, UpdateMovieTool, SearchMoviesTool, DeleteMovieTool } from "./tools/CustomDataTool";
|
|
10
10
|
|
|
11
|
+
// ============================================================================
|
|
12
|
+
// WEBHOOK EXAMPLES (Uncomment to enable)
|
|
13
|
+
// ============================================================================
|
|
14
|
+
// Webhooks receive HTTP requests from external systems
|
|
15
|
+
// See: WEBHOOK_JOB_EXAMPLES.md for detailed explanations
|
|
16
|
+
|
|
17
|
+
// import userEventWebhook from "./webhooks/UserEventWebhook";
|
|
18
|
+
// import paymentWebhook from "./webhooks/PaymentWebhook";
|
|
19
|
+
|
|
20
|
+
// ============================================================================
|
|
21
|
+
// JOB EXAMPLES (Uncomment to enable)
|
|
22
|
+
// ============================================================================
|
|
23
|
+
// Jobs are scheduled tasks that run at specific times or intervals
|
|
24
|
+
// See: WEBHOOK_JOB_EXAMPLES.md for detailed explanations
|
|
25
|
+
|
|
26
|
+
// import dailyCleanupJob from "./jobs/DailyCleanupJob";
|
|
27
|
+
// import healthCheckJob from "./jobs/HealthCheckJob";
|
|
28
|
+
// import dataMigrationJob from "./jobs/DataMigrationJob";
|
|
29
|
+
// import abandonedBasketProcessorJob from "./jobs/AbandonedBasketProcessorJob";
|
|
30
|
+
|
|
31
|
+
// ============================================================================
|
|
32
|
+
// SMART BASKET TOOL (Uncomment to enable)
|
|
33
|
+
// ============================================================================
|
|
34
|
+
// This tool creates baskets with automatic abandoned cart reminders
|
|
35
|
+
// Uses Jobs.create() to schedule one-time check 3 hours after creation
|
|
36
|
+
|
|
37
|
+
// import { CreateSmartBasketTool, CheckAbandonedBasketsTool } from "./tools/SmartBasketTool";
|
|
38
|
+
|
|
39
|
+
// ============================================================================
|
|
40
|
+
// GAME SCORE TRACKER (Uncomment to enable) - ADVANCED EXAMPLE
|
|
41
|
+
// ============================================================================
|
|
42
|
+
// Complex example showing:
|
|
43
|
+
// - Interval jobs that start at specific time
|
|
44
|
+
// - Jobs that stop themselves when condition is met
|
|
45
|
+
// - Real-time monitoring with external API integration
|
|
46
|
+
// See: COMPLEX_JOB_EXAMPLES.md for detailed explanation
|
|
47
|
+
|
|
48
|
+
// import { TrackGameScoresTool, GetGameScoresTool, StopGameTrackingTool } from "./tools/GameScoreTrackerTool";
|
|
49
|
+
|
|
11
50
|
|
|
12
51
|
// Initialize skill with tools
|
|
13
52
|
const generalSkill = new LuaSkill({
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Abandoned Basket Processor Job
|
|
3
|
+
*
|
|
4
|
+
* This job runs every 15 minutes to process basket checkout reminders.
|
|
5
|
+
* Works together with CreateSmartBasketTool to send abandoned cart notifications.
|
|
6
|
+
*
|
|
7
|
+
* Flow:
|
|
8
|
+
* 1. User creates basket → Tool schedules reminder in custom data
|
|
9
|
+
* 2. This job runs every 15 minutes
|
|
10
|
+
* 3. Checks which reminders are due
|
|
11
|
+
* 4. Checks if baskets were checked out
|
|
12
|
+
* 5. Sends reminders for abandoned baskets
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { LuaJob, Data, Baskets } from "lua-cli";
|
|
16
|
+
|
|
17
|
+
const abandonedBasketProcessorJob = new LuaJob({
|
|
18
|
+
name: "process-basket-reminders",
|
|
19
|
+
version: "1.0.0",
|
|
20
|
+
description: "Processes abandoned basket reminders",
|
|
21
|
+
context: "Runs every 15 minutes to check for abandoned baskets and send recovery emails. " +
|
|
22
|
+
"Works with basket creation tools that schedule reminders.",
|
|
23
|
+
|
|
24
|
+
// Run every 15 minutes
|
|
25
|
+
schedule: {
|
|
26
|
+
type: 'interval',
|
|
27
|
+
seconds: 900 // 15 minutes = 900 seconds
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
timeout: 120, // 2 minutes
|
|
31
|
+
|
|
32
|
+
execute: async () => {
|
|
33
|
+
console.log('🔍 Processing basket reminders...');
|
|
34
|
+
|
|
35
|
+
// Get all pending reminders
|
|
36
|
+
const remindersResponse = await Data.get('basket-reminders', {}, 1, 500);
|
|
37
|
+
const reminders = remindersResponse.data || [];
|
|
38
|
+
const now = new Date();
|
|
39
|
+
|
|
40
|
+
let processedCount = 0;
|
|
41
|
+
let abandonedCount = 0;
|
|
42
|
+
let checkedOutCount = 0;
|
|
43
|
+
|
|
44
|
+
for (const reminder of reminders) {
|
|
45
|
+
// Skip if not yet time
|
|
46
|
+
const scheduledTime = new Date(reminder.data.scheduledFor);
|
|
47
|
+
if (scheduledTime > now) continue;
|
|
48
|
+
|
|
49
|
+
// Skip if already processed
|
|
50
|
+
if (reminder.data.status !== 'pending') continue;
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
// Get the basket
|
|
54
|
+
const basketInstance = await Baskets.getById(reminder.data.basketId);
|
|
55
|
+
const basket = await basketInstance.getData();
|
|
56
|
+
|
|
57
|
+
// Check basket status
|
|
58
|
+
const isAbandoned = basket.status === 'active';
|
|
59
|
+
|
|
60
|
+
if (isAbandoned) {
|
|
61
|
+
// Basket is abandoned - send reminder
|
|
62
|
+
console.log(`🛒 Abandoned basket found: ${basket.id}`);
|
|
63
|
+
abandonedCount++;
|
|
64
|
+
|
|
65
|
+
// Calculate basket value
|
|
66
|
+
const totalValue = basket.items?.reduce((sum: number, item: any) => {
|
|
67
|
+
return sum + (item.price * item.quantity);
|
|
68
|
+
}, 0) || 0;
|
|
69
|
+
|
|
70
|
+
// Log abandoned basket
|
|
71
|
+
await Data.create('abandoned-baskets', {
|
|
72
|
+
basketId: basket.id,
|
|
73
|
+
currency: basket.currency,
|
|
74
|
+
itemCount: basket.items?.length || 0,
|
|
75
|
+
totalValue,
|
|
76
|
+
items: basket.items,
|
|
77
|
+
abandonedAt: new Date().toISOString(),
|
|
78
|
+
reminderSent: true
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// Update reminder status
|
|
82
|
+
await Data.update('basket-reminders', reminder.id, {
|
|
83
|
+
...reminder.data,
|
|
84
|
+
status: 'completed',
|
|
85
|
+
result: 'abandoned',
|
|
86
|
+
processedAt: new Date().toISOString()
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// TODO: Send actual reminder email/SMS
|
|
90
|
+
console.log(`📧 Would send reminder: "You left ${basket.items?.length || 0} items in your cart!"`);
|
|
91
|
+
|
|
92
|
+
} else {
|
|
93
|
+
// Basket was checked out
|
|
94
|
+
console.log(`✅ Basket ${basket.id} was checked out (${basket.status})`);
|
|
95
|
+
checkedOutCount++;
|
|
96
|
+
|
|
97
|
+
// Update reminder status
|
|
98
|
+
await Data.update('basket-reminders', reminder.id, {
|
|
99
|
+
...reminder.data,
|
|
100
|
+
status: 'completed',
|
|
101
|
+
result: 'checked-out',
|
|
102
|
+
processedAt: new Date().toISOString()
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
processedCount++;
|
|
107
|
+
|
|
108
|
+
} catch (error) {
|
|
109
|
+
console.error(`❌ Error processing basket ${reminder.data.basketId}:`, error);
|
|
110
|
+
|
|
111
|
+
// Mark as error
|
|
112
|
+
try {
|
|
113
|
+
await Data.update('basket-reminders', reminder.id, {
|
|
114
|
+
...reminder.data,
|
|
115
|
+
status: 'error',
|
|
116
|
+
error: String(error),
|
|
117
|
+
processedAt: new Date().toISOString()
|
|
118
|
+
});
|
|
119
|
+
} catch (updateError) {
|
|
120
|
+
console.error('Failed to update reminder status:', updateError);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
console.log('✅ Reminder processing complete');
|
|
126
|
+
console.log(`📊 Processed: ${processedCount}, Abandoned: ${abandonedCount}, Checked out: ${checkedOutCount}`);
|
|
127
|
+
|
|
128
|
+
return {
|
|
129
|
+
success: true,
|
|
130
|
+
processedCount,
|
|
131
|
+
abandonedCount,
|
|
132
|
+
checkedOutCount,
|
|
133
|
+
timestamp: new Date().toISOString()
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
export default abandonedBasketProcessorJob;
|
|
139
|
+
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Daily Cleanup Job Example
|
|
3
|
+
*
|
|
4
|
+
* This job runs daily at 2 AM to clean up old data and maintain database performance.
|
|
5
|
+
* Demonstrates: Cron scheduling, data cleanup, and error handling.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { LuaJob, Data } from "lua-cli";
|
|
9
|
+
|
|
10
|
+
const dailyCleanupJob = new LuaJob({
|
|
11
|
+
name: "daily-cleanup",
|
|
12
|
+
version: "1.0.0",
|
|
13
|
+
description: "Daily database cleanup and maintenance",
|
|
14
|
+
context: "Runs at 2 AM EST daily to remove old logs, expired sessions, and optimize data collections. " +
|
|
15
|
+
"This job helps maintain database performance and storage costs.",
|
|
16
|
+
|
|
17
|
+
// Cron schedule: Every day at 2 AM EST
|
|
18
|
+
schedule: {
|
|
19
|
+
type: 'cron',
|
|
20
|
+
expression: '0 2 * * *', // minute hour day month day-of-week
|
|
21
|
+
timezone: 'America/New_York'
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
// Give it 10 minutes to complete
|
|
25
|
+
timeout: 600,
|
|
26
|
+
|
|
27
|
+
// Retry up to 3 times if it fails
|
|
28
|
+
retry: {
|
|
29
|
+
maxAttempts: 3,
|
|
30
|
+
backoffSeconds: 60 // Wait 60s between retries
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
execute: async () => {
|
|
34
|
+
console.log('🧹 Starting daily cleanup...');
|
|
35
|
+
const startTime = Date.now();
|
|
36
|
+
|
|
37
|
+
let totalRecordsDeleted = 0;
|
|
38
|
+
|
|
39
|
+
// 1. Clean up old user events (older than 90 days)
|
|
40
|
+
const ninetyDaysAgo = new Date(Date.now() - 90 * 24 * 60 * 60 * 1000);
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
const oldEventsResponse = await Data.get('user-events', {}, 1, 1000);
|
|
44
|
+
const oldEvents = oldEventsResponse.data || [];
|
|
45
|
+
|
|
46
|
+
for (const event of oldEvents) {
|
|
47
|
+
const eventDate = new Date(event.data.receivedAt);
|
|
48
|
+
if (eventDate < ninetyDaysAgo) {
|
|
49
|
+
await Data.delete('user-events', event.id);
|
|
50
|
+
totalRecordsDeleted++;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
console.log(`✅ Deleted ${totalRecordsDeleted} old user events`);
|
|
55
|
+
} catch (error) {
|
|
56
|
+
console.error('❌ Error cleaning user events:', error);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// 2. Clean up old payment logs (older than 180 days)
|
|
60
|
+
const oneEightyDaysAgo = new Date(Date.now() - 180 * 24 * 60 * 60 * 1000);
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
const oldLogsResponse = await Data.get('payment-logs', {}, 1, 1000);
|
|
64
|
+
const oldLogs = oldLogsResponse.data || [];
|
|
65
|
+
let logsDeleted = 0;
|
|
66
|
+
|
|
67
|
+
for (const log of oldLogs) {
|
|
68
|
+
const logDate = new Date(log.data.receivedAt);
|
|
69
|
+
if (logDate < oneEightyDaysAgo) {
|
|
70
|
+
await Data.delete('payment-logs', log.id);
|
|
71
|
+
logsDeleted++;
|
|
72
|
+
totalRecordsDeleted++;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
console.log(`✅ Deleted ${logsDeleted} old payment logs`);
|
|
77
|
+
} catch (error) {
|
|
78
|
+
console.error('❌ Error cleaning payment logs:', error);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// 3. Clean up abandoned baskets (older than 7 days)
|
|
82
|
+
// Note: This would require basket API support for deletion
|
|
83
|
+
// For now, we'll just log the count
|
|
84
|
+
|
|
85
|
+
const duration = Date.now() - startTime;
|
|
86
|
+
|
|
87
|
+
console.log(`✅ Cleanup complete in ${duration}ms`);
|
|
88
|
+
|
|
89
|
+
return {
|
|
90
|
+
success: true,
|
|
91
|
+
recordsDeleted: totalRecordsDeleted,
|
|
92
|
+
duration: `${duration}ms`,
|
|
93
|
+
completedAt: new Date().toISOString(),
|
|
94
|
+
collections: ['user-events', 'payment-logs']
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
export default dailyCleanupJob;
|
|
100
|
+
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Data Migration Job Example
|
|
3
|
+
*
|
|
4
|
+
* This is a one-time job that runs at a specific date/time to migrate data.
|
|
5
|
+
* Demonstrates: One-time scheduling, data migration, and batch processing.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { LuaJob, Data } from "lua-cli";
|
|
9
|
+
|
|
10
|
+
const dataMigrationJob = new LuaJob({
|
|
11
|
+
name: "migrate-user-schema",
|
|
12
|
+
version: "1.0.0",
|
|
13
|
+
description: "One-time migration to new user event schema",
|
|
14
|
+
context: "Scheduled one-time task to migrate user events from old schema to new schema. " +
|
|
15
|
+
"Runs once at the specified time and then automatically deactivates.",
|
|
16
|
+
|
|
17
|
+
// One-time schedule: Run at specific date/time
|
|
18
|
+
schedule: {
|
|
19
|
+
type: 'once',
|
|
20
|
+
executeAt: new Date('2025-12-31T02:00:00Z') // December 31, 2025 at 2 AM UTC
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
// Give it 30 minutes for large migration
|
|
24
|
+
timeout: 1800,
|
|
25
|
+
|
|
26
|
+
// Retry important migrations
|
|
27
|
+
retry: {
|
|
28
|
+
maxAttempts: 3,
|
|
29
|
+
backoffSeconds: 300 // 5 minutes between retries
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
execute: async () => {
|
|
33
|
+
console.log('🔄 Starting data migration...');
|
|
34
|
+
const startTime = Date.now();
|
|
35
|
+
|
|
36
|
+
let totalMigrated = 0;
|
|
37
|
+
let totalErrors = 0;
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
// Get all user events with old schema
|
|
41
|
+
const oldEventsResponse = await Data.get('user-events', {}, 1, 1000);
|
|
42
|
+
const oldEvents = oldEventsResponse.data || [];
|
|
43
|
+
|
|
44
|
+
console.log(`📊 Found ${oldEvents.length} events to migrate`);
|
|
45
|
+
|
|
46
|
+
// Migrate each event
|
|
47
|
+
for (const event of oldEvents) {
|
|
48
|
+
try {
|
|
49
|
+
// Transform old schema to new schema
|
|
50
|
+
const migratedEvent = {
|
|
51
|
+
// New fields
|
|
52
|
+
eventId: event.id,
|
|
53
|
+
eventType: event.data.type || 'unknown',
|
|
54
|
+
userId: event.data.userId || event.data.user_id, // Handle both formats
|
|
55
|
+
email: event.data.email,
|
|
56
|
+
name: event.data.name,
|
|
57
|
+
|
|
58
|
+
// Preserve metadata
|
|
59
|
+
metadata: {
|
|
60
|
+
...event.data.metadata,
|
|
61
|
+
migratedFrom: 'old-schema',
|
|
62
|
+
migratedAt: new Date().toISOString()
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
// Copy timestamps
|
|
66
|
+
originalTimestamp: event.data.timestamp,
|
|
67
|
+
receivedAt: event.data.receivedAt
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// Create in new collection
|
|
71
|
+
await Data.create('user-events-v2', migratedEvent,
|
|
72
|
+
`${migratedEvent.eventType} ${migratedEvent.email}`
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
totalMigrated++;
|
|
76
|
+
|
|
77
|
+
// Log progress every 100 records
|
|
78
|
+
if (totalMigrated % 100 === 0) {
|
|
79
|
+
console.log(`✅ Migrated ${totalMigrated} records...`);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
} catch (error) {
|
|
83
|
+
console.error(`❌ Failed to migrate event ${event.id}:`, error);
|
|
84
|
+
totalErrors++;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const duration = Date.now() - startTime;
|
|
89
|
+
const successRate = ((totalMigrated / oldEvents.length) * 100).toFixed(2);
|
|
90
|
+
|
|
91
|
+
console.log(`✅ Migration complete!`);
|
|
92
|
+
console.log(`📊 Stats:`);
|
|
93
|
+
console.log(` - Total records: ${oldEvents.length}`);
|
|
94
|
+
console.log(` - Migrated: ${totalMigrated}`);
|
|
95
|
+
console.log(` - Errors: ${totalErrors}`);
|
|
96
|
+
console.log(` - Success rate: ${successRate}%`);
|
|
97
|
+
console.log(` - Duration: ${duration}ms`);
|
|
98
|
+
|
|
99
|
+
// Store migration report
|
|
100
|
+
await Data.create('migration-reports', {
|
|
101
|
+
jobName: 'migrate-user-schema',
|
|
102
|
+
totalRecords: oldEvents.length,
|
|
103
|
+
migrated: totalMigrated,
|
|
104
|
+
errors: totalErrors,
|
|
105
|
+
successRate: parseFloat(successRate),
|
|
106
|
+
duration,
|
|
107
|
+
completedAt: new Date().toISOString()
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
success: true,
|
|
112
|
+
totalRecords: oldEvents.length,
|
|
113
|
+
migrated: totalMigrated,
|
|
114
|
+
errors: totalErrors,
|
|
115
|
+
successRate: `${successRate}%`,
|
|
116
|
+
duration: `${duration}ms`
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
} catch (error) {
|
|
120
|
+
console.error('💥 Migration failed:', error);
|
|
121
|
+
|
|
122
|
+
return {
|
|
123
|
+
success: false,
|
|
124
|
+
error: String(error),
|
|
125
|
+
totalMigrated,
|
|
126
|
+
totalErrors
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
export default dataMigrationJob;
|
|
133
|
+
|