jw-automator 2.0.0 → 3.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.
@@ -0,0 +1,350 @@
1
+ # Quick Start Guide
2
+
3
+ Get up and running with jw-automator v3 in 5 minutes.
4
+
5
+ ---
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install jw-automator
11
+ ```
12
+
13
+ ---
14
+
15
+ ## Basic Example
16
+
17
+ Create a file `app.js`:
18
+
19
+ ```javascript
20
+ const Automator = require('jw-automator');
21
+
22
+ // Create automator with file-based storage
23
+ const automator = new Automator({
24
+ storage: Automator.storage.file('./my-actions.json')
25
+ });
26
+
27
+ // Register a function
28
+ automator.addFunction('sayHello', function(payload) {
29
+ console.log(`Hello, ${payload.name}!`);
30
+ });
31
+
32
+ // Add a repeating action
33
+ automator.addAction({
34
+ name: 'Greeting',
35
+ cmd: 'sayHello',
36
+ date: new Date(Date.now() + 2000), // Start in 2 seconds
37
+ payload: { name: 'World' },
38
+ repeat: {
39
+ type: 'second',
40
+ interval: 5,
41
+ limit: 3 // Run 3 times then stop
42
+ }
43
+ });
44
+
45
+ // Listen to events
46
+ automator.on('action', (event) => {
47
+ console.log(`Action executed: ${event.name}`);
48
+ });
49
+
50
+ // Start the scheduler
51
+ automator.start();
52
+
53
+ console.log('Automator started! Greeting will run 3 times.');
54
+ ```
55
+
56
+ Run it:
57
+
58
+ ```bash
59
+ node app.js
60
+ ```
61
+
62
+ ---
63
+
64
+ ## Common Patterns
65
+
66
+ ### Daily Task at Specific Time
67
+
68
+ ```javascript
69
+ automator.addAction({
70
+ name: 'Daily Backup',
71
+ cmd: 'runBackup',
72
+ date: new Date('2025-05-01T02:00:00'), // 2:00 AM
73
+ repeat: {
74
+ type: 'day',
75
+ interval: 1
76
+ }
77
+ });
78
+ ```
79
+
80
+ ### Weekday Task
81
+
82
+ ```javascript
83
+ automator.addAction({
84
+ name: 'Weekday Reminder',
85
+ cmd: 'sendReminder',
86
+ date: new Date('2025-05-01T09:00:00'), // 9:00 AM
87
+ repeat: {
88
+ type: 'weekday',
89
+ interval: 1 // Every weekday
90
+ }
91
+ });
92
+ ```
93
+
94
+ ### Every N Minutes
95
+
96
+ ```javascript
97
+ automator.addAction({
98
+ name: 'Health Check',
99
+ cmd: 'checkHealth',
100
+ date: new Date(),
101
+ repeat: {
102
+ type: 'minute',
103
+ interval: 15 // Every 15 minutes
104
+ }
105
+ });
106
+ ```
107
+
108
+ ### Limited Run Count
109
+
110
+ ```javascript
111
+ automator.addAction({
112
+ name: 'Startup Sequence',
113
+ cmd: 'initSystem',
114
+ date: new Date(),
115
+ repeat: {
116
+ type: 'second',
117
+ interval: 1,
118
+ limit: 10 // Run exactly 10 times
119
+ }
120
+ });
121
+ ```
122
+
123
+ ### End Date
124
+
125
+ ```javascript
126
+ automator.addAction({
127
+ name: 'Summer Sprinklers',
128
+ cmd: 'waterLawn',
129
+ date: new Date('2025-06-01T06:00:00'),
130
+ repeat: {
131
+ type: 'day',
132
+ interval: 1,
133
+ endDate: new Date('2025-09-01T00:00:00') // Stop after summer
134
+ }
135
+ });
136
+ ```
137
+
138
+ ---
139
+
140
+ ## Buffered vs UnBuffered
141
+
142
+ ### Buffered (Default) - Catch Up Missed Events
143
+
144
+ ```javascript
145
+ automator.addAction({
146
+ name: 'Critical Task',
147
+ cmd: 'criticalTask',
148
+ date: new Date('2025-05-01T10:00:00'),
149
+ unBuffered: false, // Execute even if delayed
150
+ repeat: { type: 'hour', interval: 1 }
151
+ });
152
+ ```
153
+
154
+ If the system is offline from 10:00 to 13:00, it will execute the 10:00, 11:00, and 12:00 occurrences when it comes back online.
155
+
156
+ ### UnBuffered - Skip Missed Events
157
+
158
+ ```javascript
159
+ automator.addAction({
160
+ name: 'Animation Frame',
161
+ cmd: 'updateAnimation',
162
+ date: new Date(),
163
+ unBuffered: true, // Only run if on time
164
+ repeat: { type: 'second', interval: 1 }
165
+ });
166
+ ```
167
+
168
+ If the system is delayed, it won't execute missed animation frames.
169
+
170
+ ---
171
+
172
+ ## Simulation
173
+
174
+ Preview what will happen in the future:
175
+
176
+ ```javascript
177
+ const tomorrow = new Date();
178
+ tomorrow.setDate(tomorrow.getDate() + 1);
179
+
180
+ const events = automator.getActionsInRange(new Date(), tomorrow);
181
+
182
+ console.log(`${events.length} events scheduled in next 24 hours`);
183
+
184
+ events.slice(0, 5).forEach(event => {
185
+ console.log(`${event.name} at ${event.scheduledTime.toLocaleString()}`);
186
+ });
187
+ ```
188
+
189
+ ---
190
+
191
+ ## Storage Options
192
+
193
+ ### File Storage
194
+
195
+ ```javascript
196
+ const automator = new Automator({
197
+ storage: Automator.storage.file('./actions.json')
198
+ });
199
+ ```
200
+
201
+ ### Memory Storage (No Persistence)
202
+
203
+ ```javascript
204
+ const automator = new Automator({
205
+ storage: Automator.storage.memory()
206
+ });
207
+ ```
208
+
209
+ ### Custom Storage
210
+
211
+ ```javascript
212
+ const automator = new Automator({
213
+ storage: {
214
+ load: function() {
215
+ // Load from database, cloud, etc.
216
+ return { actions: [...] };
217
+ },
218
+ save: function(state) {
219
+ // Save to database, cloud, etc.
220
+ }
221
+ }
222
+ });
223
+ ```
224
+
225
+ ---
226
+
227
+ ## Event Handling
228
+
229
+ ```javascript
230
+ // Scheduler ready
231
+ automator.on('ready', () => {
232
+ console.log('Scheduler started');
233
+ });
234
+
235
+ // Action executed
236
+ automator.on('action', (event) => {
237
+ console.log('Action:', event.name);
238
+ console.log('Scheduled:', event.scheduledTime);
239
+ console.log('Actual:', event.actualTime);
240
+ console.log('Count:', event.count);
241
+ });
242
+
243
+ // Action added/updated/removed
244
+ automator.on('update', (event) => {
245
+ console.log('Update:', event.operation, event.actionId);
246
+ });
247
+
248
+ // Errors
249
+ automator.on('error', (event) => {
250
+ console.error('Error:', event.message);
251
+ });
252
+ ```
253
+
254
+ ---
255
+
256
+ ## Managing Actions
257
+
258
+ ### Add
259
+
260
+ ```javascript
261
+ const id = automator.addAction({
262
+ name: 'My Task',
263
+ cmd: 'myCommand',
264
+ date: new Date(),
265
+ repeat: { type: 'hour', interval: 1 }
266
+ });
267
+ ```
268
+
269
+ ### Update
270
+
271
+ ```javascript
272
+ automator.updateActionByID(id, {
273
+ name: 'Updated Task',
274
+ repeat: { type: 'hour', interval: 2 }
275
+ });
276
+ ```
277
+
278
+ ### Remove
279
+
280
+ ```javascript
281
+ // By ID
282
+ automator.removeActionByID(id);
283
+
284
+ // By name
285
+ automator.removeActionByName('My Task');
286
+ ```
287
+
288
+ ### Query
289
+
290
+ ```javascript
291
+ // All actions
292
+ const all = automator.getActions();
293
+
294
+ // By name
295
+ const tasks = automator.getActionsByName('My Task');
296
+
297
+ // By ID
298
+ const task = automator.getActionByID(id);
299
+
300
+ // Description
301
+ const desc = automator.describeAction(id);
302
+ console.log(desc);
303
+ ```
304
+
305
+ ---
306
+
307
+ ## DST Handling
308
+
309
+ For actions that run during daylight saving time transitions:
310
+
311
+ ### Fall Back (Repeated Hour)
312
+
313
+ ```javascript
314
+ automator.addAction({
315
+ name: 'DST Aware',
316
+ cmd: 'task',
317
+ date: new Date('2025-11-02T01:30:00'), // Falls in repeated hour
318
+ repeat: {
319
+ type: 'day',
320
+ interval: 1,
321
+ dstPolicy: 'once' // Only run the first 1:30 AM
322
+ // or dstPolicy: 'twice' to run both
323
+ }
324
+ });
325
+ ```
326
+
327
+ ---
328
+
329
+ ## Graceful Shutdown
330
+
331
+ ```javascript
332
+ process.on('SIGINT', () => {
333
+ console.log('Shutting down...');
334
+ automator.stop(); // Saves state
335
+ process.exit(0);
336
+ });
337
+ ```
338
+
339
+ ---
340
+
341
+ ## Next Steps
342
+
343
+ - Read the full [README](../README.md)
344
+ - Check out [examples](../examples/)
345
+ - Review [Architecture](./ARCHITECTURE.md)
346
+ - See [Migration Guide](./MIGRATION.md) if upgrading from v1
347
+
348
+ ---
349
+
350
+ Happy Automating!
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Basic Example - jw-automator v3
3
+ *
4
+ * This example demonstrates the core features of jw-automator.
5
+ */
6
+
7
+ const Automator = require('../index');
8
+
9
+ // Create automator with file-based persistence
10
+ const automator = new Automator({
11
+ storage: Automator.storage.file('./example-actions.json'),
12
+ autoSave: true,
13
+ saveInterval: 5000
14
+ });
15
+
16
+ // Register command functions
17
+ automator.addFunction('logMessage', function(payload, event) {
18
+ console.log(`[${new Date().toLocaleTimeString()}] ${payload.message}`);
19
+ console.log(` Scheduled: ${event.scheduledTime.toLocaleTimeString()}`);
20
+ console.log(` Execution count: ${event.count + 1}`);
21
+ });
22
+
23
+ automator.addFunction('morningRoutine', function(payload) {
24
+ console.log('Good morning! Starting daily routine...');
25
+ console.log('- Check weather');
26
+ console.log('- Turn on coffee maker');
27
+ console.log('- Adjust thermostat');
28
+ });
29
+
30
+ automator.addFunction('weeklyBackup', function(payload) {
31
+ console.log('Running weekly backup...');
32
+ // Simulate backup process
33
+ console.log('Backup complete!');
34
+ });
35
+
36
+ // Listen to events
37
+ automator.on('ready', () => {
38
+ console.log('Automator started!');
39
+ console.log('Current actions:', automator.getActions().length);
40
+ });
41
+
42
+ automator.on('action', (event) => {
43
+ console.log(`\n=== Action Executed ===`);
44
+ console.log(`Name: ${event.name || 'Unnamed'}`);
45
+ console.log(`Command: ${event.cmd}`);
46
+ console.log(`======================\n`);
47
+ });
48
+
49
+ automator.on('error', (event) => {
50
+ console.error('Error:', event.message);
51
+ });
52
+
53
+ // Add actions
54
+
55
+ // 1. Every 10 seconds - demo message
56
+ automator.addAction({
57
+ name: 'Demo Message',
58
+ cmd: 'logMessage',
59
+ date: new Date(Date.now() + 5000), // Start in 5 seconds
60
+ payload: { message: 'This is a recurring message every 10 seconds' },
61
+ unBuffered: false,
62
+ repeat: {
63
+ type: 'second',
64
+ interval: 10,
65
+ limit: 6, // Run 6 times then stop
66
+ dstPolicy: 'once'
67
+ }
68
+ });
69
+
70
+ // 2. Daily morning routine at 7:00 AM
71
+ automator.addAction({
72
+ name: 'Morning Routine',
73
+ cmd: 'morningRoutine',
74
+ date: new Date(new Date().setHours(7, 0, 0, 0)),
75
+ unBuffered: false,
76
+ repeat: {
77
+ type: 'day',
78
+ interval: 1,
79
+ dstPolicy: 'once'
80
+ }
81
+ });
82
+
83
+ // 3. Weekly backup every Sunday at 2:00 AM
84
+ const nextSunday = new Date();
85
+ nextSunday.setDate(nextSunday.getDate() + (7 - nextSunday.getDay()) % 7);
86
+ nextSunday.setHours(2, 0, 0, 0);
87
+
88
+ automator.addAction({
89
+ name: 'Weekly Backup',
90
+ cmd: 'weeklyBackup',
91
+ date: nextSunday,
92
+ unBuffered: false,
93
+ repeat: {
94
+ type: 'week',
95
+ interval: 1,
96
+ dstPolicy: 'once'
97
+ }
98
+ });
99
+
100
+ // Demonstrate simulation - what will happen in the next 24 hours?
101
+ console.log('\n=== Simulation: Next 24 hours ===');
102
+ const now = new Date();
103
+ const tomorrow = new Date(now.getTime() + 24 * 60 * 60 * 1000);
104
+
105
+ const futureEvents = automator.getActionsInRange(now, tomorrow);
106
+ console.log(`${futureEvents.length} events scheduled in the next 24 hours\n`);
107
+
108
+ futureEvents.slice(0, 10).forEach((event, i) => {
109
+ console.log(`${i + 1}. ${event.name} at ${event.scheduledTime.toLocaleString()}`);
110
+ });
111
+
112
+ if (futureEvents.length > 10) {
113
+ console.log(`... and ${futureEvents.length - 10} more events`);
114
+ }
115
+
116
+ console.log('\n=== Current Actions ===');
117
+ automator.getActions().forEach((action) => {
118
+ console.log(automator.describeAction(action.id));
119
+ console.log('---');
120
+ });
121
+
122
+ // Start the automator
123
+ console.log('\n=== Starting Automator ===\n');
124
+ automator.start();
125
+
126
+ // Graceful shutdown on Ctrl+C
127
+ process.on('SIGINT', () => {
128
+ console.log('\n\nShutting down automator...');
129
+ automator.stop();
130
+ console.log('Goodbye!');
131
+ process.exit(0);
132
+ });
133
+
134
+ // Keep the process running
135
+ console.log('Press Ctrl+C to stop\n');
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Hello World - jw-automator v3
3
+ *
4
+ * The simplest possible example.
5
+ */
6
+
7
+ const Automator = require('../index');
8
+
9
+ // Create automator (in-memory, no persistence)
10
+ const automator = new Automator({
11
+ storage: Automator.storage.memory()
12
+ });
13
+
14
+ // Register a function
15
+ automator.addFunction('sayHello', function() {
16
+ console.log('Hello, World!');
17
+ });
18
+
19
+ // Add an action that runs every 3 seconds, 5 times
20
+ automator.addAction({
21
+ cmd: 'sayHello',
22
+ date: new Date(Date.now() + 1000), // Start in 1 second
23
+ repeat: {
24
+ type: 'second',
25
+ interval: 3,
26
+ limit: 5
27
+ }
28
+ });
29
+
30
+ // Start the scheduler
31
+ automator.start();
32
+
33
+ console.log('Automator started! Will say hello 5 times, every 3 seconds.');
34
+
35
+ // Auto-stop after 20 seconds
36
+ setTimeout(() => {
37
+ automator.stop();
38
+ console.log('Goodbye!');
39
+ process.exit(0);
40
+ }, 20000);
@@ -0,0 +1,149 @@
1
+ /**
2
+ * IoT Sensor Example - jw-automator v3
3
+ *
4
+ * Demonstrates using jw-automator for sensor reading and data collection
5
+ * typical in IoT and home automation scenarios.
6
+ */
7
+
8
+ const Automator = require('../index');
9
+
10
+ // Create automator
11
+ const automator = new Automator({
12
+ storage: Automator.storage.memory() // Use memory storage for this example
13
+ });
14
+
15
+ // Simulated sensor data
16
+ const sensorData = {
17
+ temperature: 22.5,
18
+ humidity: 45,
19
+ pressure: 1013.25
20
+ };
21
+
22
+ // Simulate sensor reading
23
+ function readSensor() {
24
+ sensorData.temperature += (Math.random() - 0.5) * 2;
25
+ sensorData.humidity += (Math.random() - 0.5) * 5;
26
+ sensorData.pressure += (Math.random() - 0.5) * 2;
27
+
28
+ return {
29
+ temperature: sensorData.temperature.toFixed(2),
30
+ humidity: sensorData.humidity.toFixed(1),
31
+ pressure: sensorData.pressure.toFixed(2),
32
+ timestamp: new Date()
33
+ };
34
+ }
35
+
36
+ // Register sensor functions
37
+ automator.addFunction('readTemperature', function() {
38
+ const reading = readSensor();
39
+ console.log(`[TEMP] ${reading.temperature}°C at ${reading.timestamp.toLocaleTimeString()}`);
40
+ });
41
+
42
+ automator.addFunction('readHumidity', function() {
43
+ const reading = readSensor();
44
+ console.log(`[HUMID] ${reading.humidity}% at ${reading.timestamp.toLocaleTimeString()}`);
45
+ });
46
+
47
+ automator.addFunction('fullSensorSweep', function() {
48
+ const reading = readSensor();
49
+ console.log('\n=== Full Sensor Sweep ===');
50
+ console.log(`Time: ${reading.timestamp.toLocaleString()}`);
51
+ console.log(`Temperature: ${reading.temperature}°C`);
52
+ console.log(`Humidity: ${reading.humidity}%`);
53
+ console.log(`Pressure: ${reading.pressure} hPa`);
54
+ console.log('========================\n');
55
+ });
56
+
57
+ automator.addFunction('dailyReport', function() {
58
+ console.log('\n*** DAILY SENSOR REPORT ***');
59
+ console.log('Generated at:', new Date().toLocaleString());
60
+ console.log('Current readings:', readSensor());
61
+ console.log('Report complete.');
62
+ console.log('***************************\n');
63
+ });
64
+
65
+ // Add sensor reading actions
66
+
67
+ // 1. Temperature reading every 5 seconds (for 1 minute demo)
68
+ automator.addAction({
69
+ name: 'Temperature Reading',
70
+ cmd: 'readTemperature',
71
+ date: new Date(Date.now() + 2000),
72
+ unBuffered: false, // Catch up if delayed
73
+ repeat: {
74
+ type: 'second',
75
+ interval: 5,
76
+ limit: 12 // Stop after 12 readings (1 minute)
77
+ }
78
+ });
79
+
80
+ // 2. Humidity reading every 10 seconds
81
+ automator.addAction({
82
+ name: 'Humidity Reading',
83
+ cmd: 'readHumidity',
84
+ date: new Date(Date.now() + 3000),
85
+ unBuffered: false,
86
+ repeat: {
87
+ type: 'second',
88
+ interval: 10,
89
+ limit: 6 // Stop after 6 readings
90
+ }
91
+ });
92
+
93
+ // 3. Full sensor sweep every 30 seconds
94
+ automator.addAction({
95
+ name: 'Full Sensor Sweep',
96
+ cmd: 'fullSensorSweep',
97
+ date: new Date(Date.now() + 5000),
98
+ unBuffered: false,
99
+ repeat: {
100
+ type: 'second',
101
+ interval: 30,
102
+ limit: 3 // Stop after 3 sweeps
103
+ }
104
+ });
105
+
106
+ // 4. Daily report at 6:00 AM (won't run in this demo, but shows the pattern)
107
+ const tomorrow6AM = new Date();
108
+ tomorrow6AM.setDate(tomorrow6AM.getDate() + 1);
109
+ tomorrow6AM.setHours(6, 0, 0, 0);
110
+
111
+ automator.addAction({
112
+ name: 'Daily Report',
113
+ cmd: 'dailyReport',
114
+ date: tomorrow6AM,
115
+ unBuffered: false,
116
+ repeat: {
117
+ type: 'day',
118
+ interval: 1
119
+ }
120
+ });
121
+
122
+ // Events
123
+ automator.on('ready', () => {
124
+ console.log('IoT Sensor Monitor Started');
125
+ console.log('================================\n');
126
+ });
127
+
128
+ automator.on('action', (event) => {
129
+ // Actions already log themselves
130
+ });
131
+
132
+ // Start
133
+ automator.start();
134
+
135
+ console.log('Sensor readings starting in 2 seconds...');
136
+ console.log('This demo will run for about 90 seconds.\n');
137
+
138
+ // Auto-stop after 90 seconds
139
+ setTimeout(() => {
140
+ console.log('\n\nDemo complete. Stopping automator...');
141
+ automator.stop();
142
+
143
+ console.log('\nFinal action summary:');
144
+ automator.getActions().forEach(action => {
145
+ console.log(`- ${action.name}: ${action.count} executions`);
146
+ });
147
+
148
+ process.exit(0);
149
+ }, 90000);
package/index.js ADDED
@@ -0,0 +1,7 @@
1
+ /**
2
+ * jw-automator v3
3
+ *
4
+ * A resilient, local-time, 1-second precision automation scheduler for Node.js
5
+ */
6
+
7
+ module.exports = require('./src/Automator');