s3db.js 9.1.0 → 9.2.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/PLUGINS.md CHANGED
@@ -18,6 +18,9 @@
18
18
  - [📊 Metrics Plugin](#-metrics-plugin)
19
19
  - [🔄 Replicator Plugin](#-replicator-plugin)
20
20
  - [📬 Queue Consumer Plugin](#-queue-consumer-plugin)
21
+ - [🤖 State Machine Plugin](#-state-machine-plugin)
22
+ - [💾 Backup Plugin](#-backup-plugin)
23
+ - [⏰ Scheduler Plugin](#-scheduler-plugin)
21
24
  - [🔧 Plugin Development](#-plugin-development)
22
25
  - [💡 Plugin Combinations](#-plugin-combinations)
23
26
  - [🎯 Best Practices](#-best-practices)
@@ -26,22 +29,68 @@
26
29
 
27
30
  ## 🚀 Getting Started with Plugins
28
31
 
29
- Plugins extend s3db.js with additional functionality. They can be used individually or combined for powerful workflows.
32
+ Plugins extend s3db.js with additional functionality using a **driver-based architecture**. They can be used individually or combined for powerful workflows.
33
+
34
+ ### Plugin Architecture
35
+
36
+ Most s3db.js plugins follow a **driver pattern** where you specify:
37
+ - **`driver`**: The storage/connection type (`filesystem`, `s3`, `multi`, etc.)
38
+ - **`config`**: Driver-specific configuration options
39
+ - **Plugin options**: Global settings that apply across drivers
30
40
 
31
41
  ### Basic Plugin Usage
32
42
 
33
43
  ```javascript
34
- import { S3db, CachePlugin, CostsPlugin } from 's3db.js';
44
+ import { S3db, CachePlugin, BackupPlugin, CostsPlugin } from 's3db.js';
35
45
 
36
46
  const s3db = new S3db({
37
- connectionString: "s3://ACCESS_KEY:SECRET_KEY@BUCKET_NAME/databases/myapp",
38
- plugins: [
39
- new CachePlugin(),
40
- CostsPlugin // Some plugins are static objects
41
- ]
47
+ connectionString: "s3://ACCESS_KEY:SECRET_KEY@BUCKET_NAME/databases/myapp"
42
48
  });
43
49
 
44
50
  await s3db.connect();
51
+
52
+ // Driver-based plugins (most common)
53
+ await s3db.usePlugin(new CachePlugin({
54
+ driver: 'memory',
55
+ config: { maxSize: 1000 }
56
+ }));
57
+
58
+ await s3db.usePlugin(new BackupPlugin({
59
+ driver: 'filesystem',
60
+ config: { path: './backups/{date}/' }
61
+ }));
62
+
63
+ // Static utility plugins
64
+ await s3db.usePlugin(CostsPlugin);
65
+ ```
66
+
67
+ ### Driver-Based Configuration Pattern
68
+
69
+ ```javascript
70
+ // Single driver example
71
+ new SomePlugin({
72
+ driver: 'driverType',
73
+ config: {
74
+ // Driver-specific options
75
+ option1: 'value1',
76
+ option2: 'value2'
77
+ },
78
+ // Global plugin options
79
+ verbose: true,
80
+ timeout: 30000
81
+ });
82
+
83
+ // Multi-driver example
84
+ new SomePlugin({
85
+ driver: 'multi',
86
+ config: {
87
+ strategy: 'all',
88
+ destinations: [
89
+ { driver: 'driver1', config: {...} },
90
+ { driver: 'driver2', config: {...} }
91
+ ]
92
+ }
93
+ });
45
94
  ```
46
95
 
47
96
  ### Plugin Types
@@ -57,24 +106,72 @@ await s3db.connect();
57
106
 
58
107
  ## 💾 Cache Plugin
59
108
 
60
- Intelligent caching system that reduces S3 API calls and improves performance by storing frequently accessed data in memory or S3.
109
+ **Driver-Based Caching System** - Intelligent caching that reduces S3 API calls and improves performance using configurable storage drivers.
61
110
 
62
- ### Quick Start
111
+ > 🏎️ **Performance**: Dramatically reduces S3 costs and latency by caching frequently accessed data.
112
+
113
+ ### 🚀 Quick Start
63
114
 
115
+ #### Memory Driver (Fast & Temporary)
64
116
  ```javascript
65
117
  import { S3db, CachePlugin } from 's3db.js';
66
118
 
67
119
  const s3db = new S3db({
68
120
  connectionString: "s3://ACCESS_KEY:SECRET_KEY@BUCKET_NAME/databases/myapp",
69
- plugins: [new CachePlugin()]
121
+ plugins: [
122
+ new CachePlugin({
123
+ driver: 'memory',
124
+ ttl: 300000, // 5 minutes
125
+ maxSize: 1000, // Max 1000 items
126
+ config: {
127
+ evictionPolicy: 'lru',
128
+ enableStats: true
129
+ }
130
+ })
131
+ ]
70
132
  });
71
133
 
72
134
  await s3db.connect();
73
135
 
74
- // Cache is automatically used for read operations
136
+ // Cache automatically intercepts read operations
75
137
  const users = s3db.resource('users');
76
- await users.count(); // Cached for default TTL
77
- await users.list(); // Cached result
138
+ await users.count(); // Cached for 5 minutes
139
+ await users.list(); // Cached result
140
+ ```
141
+
142
+ #### S3 Driver (Persistent & Shared)
143
+ ```javascript
144
+ const s3db = new S3db({
145
+ connectionString: "s3://ACCESS_KEY:SECRET_KEY@BUCKET_NAME/databases/myapp",
146
+ plugins: [
147
+ new CachePlugin({
148
+ driver: 's3',
149
+ ttl: 1800000, // 30 minutes
150
+ config: {
151
+ bucket: 'my-cache-bucket', // Optional: separate bucket
152
+ keyPrefix: 'cache/', // Cache key prefix
153
+ storageClass: 'STANDARD' // S3 storage class
154
+ }
155
+ })
156
+ ]
157
+ });
158
+ ```
159
+
160
+ #### Filesystem Driver (Local & Fast)
161
+ ```javascript
162
+ const s3db = new S3db({
163
+ connectionString: "s3://ACCESS_KEY:SECRET_KEY@BUCKET_NAME/databases/myapp",
164
+ plugins: [
165
+ new CachePlugin({
166
+ driver: 'filesystem',
167
+ config: {
168
+ path: './cache',
169
+ partitionAware: true,
170
+ partitionStrategy: 'hierarchical'
171
+ }
172
+ })
173
+ ]
174
+ });
78
175
  ```
79
176
 
80
177
  ### ⚙️ Configuration Parameters
@@ -4143,6 +4240,758 @@ const s3db = new S3db({
4143
4240
 
4144
4241
  ---
4145
4242
 
4243
+ ## 🤖 State Machine Plugin
4244
+
4245
+ Finite state machine capabilities for managing complex workflows and business processes with well-defined states and transitions.
4246
+
4247
+ ### ⚡ Quick Start
4248
+
4249
+ ```javascript
4250
+ import { S3db, StateMachinePlugin } from 's3db.js';
4251
+
4252
+ const s3db = new S3db({
4253
+ connectionString: "s3://ACCESS_KEY:SECRET_KEY@BUCKET_NAME/databases/myapp",
4254
+ plugins: [
4255
+ new StateMachinePlugin({
4256
+ stateMachines: {
4257
+ order_processing: {
4258
+ initialState: 'pending',
4259
+ states: {
4260
+ pending: {
4261
+ on: { CONFIRM: 'confirmed', CANCEL: 'cancelled' }
4262
+ },
4263
+ confirmed: {
4264
+ on: { PREPARE: 'preparing', CANCEL: 'cancelled' },
4265
+ entry: 'onConfirmed'
4266
+ },
4267
+ preparing: {
4268
+ on: { SHIP: 'shipped', CANCEL: 'cancelled' },
4269
+ guards: { SHIP: 'canShip' }
4270
+ },
4271
+ shipped: {
4272
+ on: { DELIVER: 'delivered', RETURN: 'returned' }
4273
+ },
4274
+ delivered: { type: 'final' },
4275
+ cancelled: { type: 'final' },
4276
+ returned: { type: 'final' }
4277
+ }
4278
+ }
4279
+ },
4280
+ actions: {
4281
+ onConfirmed: async (context, event, machine) => {
4282
+ console.log(`Order ${context.id} confirmed!`);
4283
+ return { action: 'confirmed', timestamp: new Date() };
4284
+ }
4285
+ },
4286
+ guards: {
4287
+ canShip: async (context, event, machine) => {
4288
+ const inventory = await machine.database.resource('inventory').get(context.productId);
4289
+ return inventory && inventory.quantity >= context.quantity;
4290
+ }
4291
+ }
4292
+ })
4293
+ ]
4294
+ });
4295
+
4296
+ await s3db.connect();
4297
+
4298
+ // Initialize entity with state machine
4299
+ await s3db.plugins.stateMachine.initializeEntity('order_processing', 'order123');
4300
+
4301
+ // Send events to trigger transitions
4302
+ await s3db.plugins.stateMachine.send('order_processing', 'order123', 'CONFIRM', {
4303
+ id: 'order123',
4304
+ productId: 'prod1',
4305
+ quantity: 2
4306
+ });
4307
+
4308
+ // Get current state
4309
+ const state = await s3db.plugins.stateMachine.getState('order_processing', 'order123');
4310
+ console.log('Current state:', state); // 'confirmed'
4311
+ ```
4312
+
4313
+ ### ⚙️ Configuration Parameters
4314
+
4315
+ | Parameter | Type | Default | Description |
4316
+ |-----------|------|---------|-------------|
4317
+ | `stateMachines` | object | `{}` | State machine definitions |
4318
+ | `actions` | object | `{}` | Action functions for state entry/exit |
4319
+ | `guards` | object | `{}` | Guard functions for transition validation |
4320
+ | `persistTransitions` | boolean | `true` | Store transition history in database |
4321
+ | `transitionLogResource` | string | `'transitions'` | Resource name for transition log |
4322
+ | `stateResource` | string | `'entity_states'` | Resource name for current states |
4323
+ | `verbose` | boolean | `false` | Enable detailed logging |
4324
+
4325
+ ### State Machine Definition Structure
4326
+
4327
+ ```javascript
4328
+ stateMachines: {
4329
+ machine_name: {
4330
+ initialState: 'start_state',
4331
+ states: {
4332
+ state_name: {
4333
+ on: { EVENT_NAME: 'target_state' }, // Transitions
4334
+ entry: 'action_name', // Action on state entry
4335
+ exit: 'action_name', // Action on state exit
4336
+ guards: { EVENT_NAME: 'guard_name' }, // Transition guards
4337
+ meta: { custom: 'metadata' }, // Additional metadata
4338
+ type: 'final' // Mark as final state
4339
+ }
4340
+ }
4341
+ }
4342
+ }
4343
+ ```
4344
+
4345
+ ### API Methods
4346
+
4347
+ ```javascript
4348
+ // Entity management
4349
+ await stateMachine.initializeEntity(machineId, entityId, context);
4350
+ const state = await stateMachine.getState(machineId, entityId);
4351
+ const result = await stateMachine.send(machineId, entityId, event, context);
4352
+
4353
+ // State information
4354
+ const events = stateMachine.getValidEvents(machineId, entityId);
4355
+ const definition = stateMachine.getMachineDefinition(machineId);
4356
+ const machines = stateMachine.getMachines();
4357
+
4358
+ // History and visualization
4359
+ const history = await stateMachine.getTransitionHistory(machineId, entityId);
4360
+ const dot = stateMachine.visualize(machineId); // Graphviz DOT format
4361
+ ```
4362
+
4363
+ ### Events
4364
+
4365
+ ```javascript
4366
+ stateMachine.on('initialized', ({ machines }) => {
4367
+ console.log('Initialized machines:', machines);
4368
+ });
4369
+
4370
+ stateMachine.on('transition', ({ machineId, entityId, from, to, event, context }) => {
4371
+ console.log(`${entityId}: ${from} → ${to} via ${event}`);
4372
+ });
4373
+
4374
+ stateMachine.on('action_error', ({ actionName, error, machineId, entityId }) => {
4375
+ console.error(`Action ${actionName} failed:`, error);
4376
+ });
4377
+ ```
4378
+
4379
+ ---
4380
+
4381
+ ## 💾 Backup Plugin
4382
+
4383
+ **Driver-Based Backup System** - Comprehensive database backup and restore capabilities with configurable drivers, compression, encryption, and retention policies.
4384
+
4385
+ > ⚡ **NEW**: Driver-based architecture supports filesystem, S3, and multi-destination backups with flexible strategies.
4386
+
4387
+ ### 🚀 Quick Start
4388
+
4389
+ #### Single Driver (Filesystem)
4390
+ ```javascript
4391
+ import { S3db, BackupPlugin } from 's3db.js';
4392
+
4393
+ const s3db = new S3db({
4394
+ connectionString: "s3://ACCESS_KEY:SECRET_KEY@BUCKET_NAME/databases/myapp"
4395
+ });
4396
+
4397
+ await s3db.connect();
4398
+
4399
+ // Install backup plugin with filesystem driver
4400
+ const backupPlugin = new BackupPlugin({
4401
+ driver: 'filesystem',
4402
+ config: {
4403
+ path: './backups/{date}/',
4404
+ compression: 'gzip'
4405
+ },
4406
+ retention: {
4407
+ daily: 7,
4408
+ weekly: 4,
4409
+ monthly: 12
4410
+ }
4411
+ });
4412
+
4413
+ await s3db.usePlugin(backupPlugin);
4414
+
4415
+ // Create backups
4416
+ const fullBackup = await backupPlugin.backup('full');
4417
+ console.log('Backup ID:', fullBackup.id);
4418
+
4419
+ // List and restore
4420
+ const backups = await backupPlugin.listBackups();
4421
+ await backupPlugin.restore(fullBackup.id);
4422
+ ```
4423
+
4424
+ #### Single Driver (S3)
4425
+ ```javascript
4426
+ const backupPlugin = new BackupPlugin({
4427
+ driver: 's3',
4428
+ config: {
4429
+ bucket: 'my-backup-bucket',
4430
+ path: 'database/{date}/',
4431
+ storageClass: 'STANDARD_IA',
4432
+ serverSideEncryption: 'AES256'
4433
+ },
4434
+ compression: 'gzip',
4435
+ verification: true
4436
+ });
4437
+ ```
4438
+
4439
+ #### Multi-Driver (Multiple Destinations)
4440
+ ```javascript
4441
+ const backupPlugin = new BackupPlugin({
4442
+ driver: 'multi',
4443
+ config: {
4444
+ strategy: 'all', // 'all', 'any', 'priority'
4445
+ destinations: [
4446
+ {
4447
+ driver: 'filesystem',
4448
+ config: { path: '/local/backups/{date}/' }
4449
+ },
4450
+ {
4451
+ driver: 's3',
4452
+ config: {
4453
+ bucket: 'remote-backups',
4454
+ storageClass: 'GLACIER'
4455
+ }
4456
+ }
4457
+ ]
4458
+ }
4459
+ });
4460
+ ```
4461
+
4462
+ ### 🎯 Driver Types
4463
+
4464
+ #### 📁 Filesystem Driver
4465
+ **Perfect for**: Local backups, network storage, development
4466
+
4467
+ ```javascript
4468
+ {
4469
+ driver: 'filesystem',
4470
+ config: {
4471
+ path: '/backups/{date}/', // Template path with variables
4472
+ permissions: 0o644, // File permissions
4473
+ directoryPermissions: 0o755 // Directory permissions
4474
+ }
4475
+ }
4476
+ ```
4477
+
4478
+ **Path Templates:**
4479
+ - `{date}` → `2024-03-15`
4480
+ - `{time}` → `14-30-45`
4481
+ - `{year}` → `2024`
4482
+ - `{month}` → `03`
4483
+ - `{day}` → `15`
4484
+ - `{backupId}` → `full-2024-03-15T14-30-45-abc123`
4485
+ - `{type}` → `full` | `incremental`
4486
+
4487
+ #### ☁️ S3 Driver
4488
+ **Perfect for**: Cloud backups, long-term storage, disaster recovery
4489
+
4490
+ ```javascript
4491
+ {
4492
+ driver: 's3',
4493
+ config: {
4494
+ bucket: 'my-backup-bucket', // S3 bucket (optional, uses database bucket)
4495
+ path: 'backups/{date}/', // S3 key prefix with templates
4496
+ storageClass: 'STANDARD_IA', // S3 storage class
4497
+ serverSideEncryption: 'AES256', // Server-side encryption
4498
+ client: customS3Client // Custom S3 client (optional)
4499
+ }
4500
+ }
4501
+ ```
4502
+
4503
+ **Storage Classes:** `STANDARD`, `STANDARD_IA`, `ONEZONE_IA`, `REDUCED_REDUNDANCY`, `GLACIER`, `DEEP_ARCHIVE`
4504
+
4505
+ #### 🔄 Multi Driver
4506
+ **Perfect for**: Redundancy, hybrid storage, complex backup strategies
4507
+
4508
+ ```javascript
4509
+ {
4510
+ driver: 'multi',
4511
+ config: {
4512
+ strategy: 'all', // Backup strategy
4513
+ concurrency: 3, // Max concurrent uploads
4514
+ destinations: [
4515
+ { driver: 'filesystem', config: {...} },
4516
+ { driver: 's3', config: {...} }
4517
+ ]
4518
+ }
4519
+ }
4520
+ ```
4521
+
4522
+ **Strategies:**
4523
+ - **`all`**: Upload to all destinations (fail if any fails)
4524
+ - **`any`**: Upload to all, succeed if at least one succeeds
4525
+ - **`priority`**: Try destinations in order, stop on first success
4526
+
4527
+ ### 🔧 Configuration Parameters
4528
+
4529
+ | Parameter | Type | Default | Description |
4530
+ |-----------|------|---------|-------------|
4531
+ | **`driver`** | `string` | `'filesystem'` | Driver type: `filesystem`, `s3`, `multi` |
4532
+ | **`config`** | `object` | `{}` | Driver-specific configuration |
4533
+ | `retention` | `object` | `{}` | Retention policy (GFS rotation) |
4534
+ | `include` | `array` | `null` | Resources to include (null = all) |
4535
+ | `exclude` | `array` | `[]` | Resources to exclude |
4536
+ | `compression` | `string` | `'gzip'` | `'none'`, `'gzip'`, `'brotli'`, `'deflate'` |
4537
+ | `encryption` | `object` | `null` | Encryption configuration |
4538
+ | `verification` | `boolean` | `true` | Verify backup integrity |
4539
+ | `tempDir` | `string` | `'./tmp/backups'` | Temporary working directory |
4540
+ | `verbose` | `boolean` | `false` | Enable detailed logging |
4541
+
4542
+ ### 🎛️ Backup Types & Operations
4543
+
4544
+ ```javascript
4545
+ // Full backup - complete database snapshot
4546
+ const fullBackup = await backupPlugin.backup('full');
4547
+ console.log(`✓ Full backup: ${fullBackup.id} (${fullBackup.size} bytes)`);
4548
+
4549
+ // Incremental backup - changes since last backup
4550
+ const incrementalBackup = await backupPlugin.backup('incremental');
4551
+
4552
+ // Selective backup - specific resources only
4553
+ const selectiveBackup = await backupPlugin.backup('full', {
4554
+ resources: ['users', 'posts']
4555
+ });
4556
+
4557
+ // Custom backup type
4558
+ const customBackup = await backupPlugin.backup('weekly-snapshot');
4559
+ ```
4560
+
4561
+ ### 📋 Backup Management
4562
+
4563
+ ```javascript
4564
+ // List all backups
4565
+ const allBackups = await backupPlugin.listBackups();
4566
+
4567
+ // List with filters
4568
+ const recentBackups = await backupPlugin.listBackups({
4569
+ limit: 10,
4570
+ prefix: 'full-2024'
4571
+ });
4572
+
4573
+ // Get backup status
4574
+ const status = await backupPlugin.getBackupStatus(backupId);
4575
+ console.log(`Status: ${status.status}, Size: ${status.size}`);
4576
+
4577
+ // Restore operations
4578
+ await backupPlugin.restore(backupId); // Full restore
4579
+ await backupPlugin.restore(backupId, { overwrite: true }); // Overwrite existing
4580
+ await backupPlugin.restore(backupId, {
4581
+ resources: ['users']
4582
+ }); // Selective restore
4583
+ ```
4584
+
4585
+ ### 🔄 Legacy Format Support
4586
+
4587
+ The plugin automatically converts legacy `destinations` format:
4588
+
4589
+ ```javascript
4590
+ // ❌ Old format (still works)
4591
+ new BackupPlugin({
4592
+ destinations: [
4593
+ { type: 'filesystem', path: '/backups/' }
4594
+ ]
4595
+ });
4596
+
4597
+ // ✅ Automatically converted to:
4598
+ // driver: 'multi'
4599
+ // config: { destinations: [{ driver: 'filesystem', config: { path: '/backups/' } }] }
4600
+ ```
4601
+
4602
+ ### 📊 Retention Policies (GFS)
4603
+
4604
+ Grandfather-Father-Son rotation keeps backups efficiently:
4605
+
4606
+ ```javascript
4607
+ retention: {
4608
+ daily: 7, // Keep 7 daily backups
4609
+ weekly: 4, // Keep 4 weekly backups
4610
+ monthly: 12, // Keep 12 monthly backups
4611
+ yearly: 3 // Keep 3 yearly backups
4612
+ }
4613
+ ```
4614
+
4615
+ ### 🎣 Hooks & Events
4616
+
4617
+ ```javascript
4618
+ const backupPlugin = new BackupPlugin({
4619
+ driver: 'filesystem',
4620
+ config: { path: './backups/' },
4621
+
4622
+ // Lifecycle hooks
4623
+ onBackupStart: async (type, { backupId }) => {
4624
+ console.log(`🚀 Starting ${type} backup: ${backupId}`);
4625
+ await notifySlack(`Backup ${backupId} started`);
4626
+ },
4627
+
4628
+ onBackupComplete: async (type, stats) => {
4629
+ console.log(`✅ ${type} backup completed:`, {
4630
+ id: stats.backupId,
4631
+ size: `${Math.round(stats.size / 1024)}KB`,
4632
+ duration: `${stats.duration}ms`,
4633
+ destinations: stats.driverInfo
4634
+ });
4635
+ },
4636
+
4637
+ onBackupError: async (type, { backupId, error }) => {
4638
+ console.error(`❌ Backup ${backupId} failed:`, error.message);
4639
+ await alertOps(error);
4640
+ }
4641
+ });
4642
+
4643
+ // Event listeners
4644
+ backupPlugin.on('backup_start', ({ id, type }) => {
4645
+ updateDashboard(`Backup ${id} started`);
4646
+ });
4647
+
4648
+ backupPlugin.on('backup_complete', ({ id, type, size, duration }) => {
4649
+ metrics.record('backup.completed', { type, size, duration });
4650
+ });
4651
+
4652
+ backupPlugin.on('restore_complete', ({ id, restored }) => {
4653
+ console.log(`Restored ${restored.length} resources from ${id}`);
4654
+ });
4655
+ ```
4656
+
4657
+ ### 🔒 Advanced Security
4658
+
4659
+ ```javascript
4660
+ const secureBackupPlugin = new BackupPlugin({
4661
+ driver: 's3',
4662
+ config: {
4663
+ bucket: 'secure-backups',
4664
+ storageClass: 'STANDARD_IA',
4665
+ serverSideEncryption: 'aws:kms',
4666
+ kmsKeyId: 'arn:aws:kms:region:account:key/key-id'
4667
+ },
4668
+
4669
+ // Client-side encryption (before upload)
4670
+ encryption: {
4671
+ algorithm: 'AES-256-GCM',
4672
+ key: process.env.BACKUP_ENCRYPTION_KEY,
4673
+ keyDerivation: {
4674
+ algorithm: 'PBKDF2',
4675
+ iterations: 100000,
4676
+ salt: 'backup-salt-2024'
4677
+ }
4678
+ },
4679
+
4680
+ // Integrity verification
4681
+ verification: true,
4682
+
4683
+ // Compression for efficiency
4684
+ compression: 'gzip'
4685
+ });
4686
+ ```
4687
+
4688
+ ### 🚀 Production Examples
4689
+
4690
+ #### Enterprise Multi-Region Setup
4691
+ ```javascript
4692
+ const enterpriseBackup = new BackupPlugin({
4693
+ driver: 'multi',
4694
+ config: {
4695
+ strategy: 'all',
4696
+ destinations: [
4697
+ {
4698
+ driver: 's3',
4699
+ config: {
4700
+ bucket: 'backups-us-east-1',
4701
+ path: 'production/{date}/',
4702
+ storageClass: 'STANDARD_IA'
4703
+ }
4704
+ },
4705
+ {
4706
+ driver: 's3',
4707
+ config: {
4708
+ bucket: 'backups-eu-west-1',
4709
+ path: 'production/{date}/',
4710
+ storageClass: 'STANDARD_IA'
4711
+ }
4712
+ },
4713
+ {
4714
+ driver: 'filesystem',
4715
+ config: {
4716
+ path: '/mnt/backup-nas/s3db/{date}/'
4717
+ }
4718
+ }
4719
+ ]
4720
+ },
4721
+ retention: {
4722
+ daily: 30,
4723
+ weekly: 12,
4724
+ monthly: 24,
4725
+ yearly: 7
4726
+ },
4727
+ verification: true,
4728
+ compression: 'gzip'
4729
+ });
4730
+ ```
4731
+
4732
+ #### Development Quick Backup
4733
+ ```javascript
4734
+ const devBackup = new BackupPlugin({
4735
+ driver: 'filesystem',
4736
+ config: {
4737
+ path: './dev-backups/{date}/'
4738
+ },
4739
+ compression: 'none',
4740
+ verification: false,
4741
+ verbose: true,
4742
+ retention: { daily: 3 }
4743
+ });
4744
+ ```
4745
+
4746
+ ### 🎯 CLI Integration
4747
+
4748
+ The BackupPlugin works with s3db CLI commands:
4749
+
4750
+ ```bash
4751
+ # Create backups
4752
+ s3db backup full --connection "s3://key:secret@bucket"
4753
+ s3db backup incremental --connection "s3://key:secret@bucket"
4754
+
4755
+ # List and status
4756
+ s3db backup --list --connection "s3://key:secret@bucket"
4757
+ s3db backup --status backup-id --connection "s3://key:secret@bucket"
4758
+
4759
+ # Restore operations
4760
+ s3db restore backup-id --connection "s3://key:secret@bucket"
4761
+ s3db restore backup-id --overwrite --connection "s3://key:secret@bucket"
4762
+ ```
4763
+
4764
+ > **Note**: CLI requires the BackupPlugin to be installed in the database instance.
4765
+
4766
+ ### 🔍 Driver Information
4767
+
4768
+ ```javascript
4769
+ // Get driver details
4770
+ const driverInfo = backupPlugin.driver.getStorageInfo();
4771
+ console.log('Driver type:', driverInfo.type);
4772
+ console.log('Configuration:', driverInfo.config);
4773
+
4774
+ // Multi-driver details
4775
+ if (driverInfo.type === 'multi') {
4776
+ console.log('Strategy:', driverInfo.strategy);
4777
+ driverInfo.destinations.forEach((dest, i) => {
4778
+ console.log(`Destination ${i}:`, dest.driver, dest.info);
4779
+ });
4780
+ }
4781
+ ```
4782
+
4783
+ ---
4784
+
4785
+ ## ⏰ Scheduler Plugin
4786
+
4787
+ Robust job scheduling capabilities with cron expressions, retry logic, and comprehensive monitoring for automated tasks.
4788
+
4789
+ ### ⚡ Quick Start
4790
+
4791
+ ```javascript
4792
+ import { S3db, SchedulerPlugin } from 's3db.js';
4793
+
4794
+ const s3db = new S3db({
4795
+ connectionString: "s3://ACCESS_KEY:SECRET_KEY@BUCKET_NAME/databases/myapp",
4796
+ plugins: [
4797
+ new SchedulerPlugin({
4798
+ timezone: 'America/Sao_Paulo',
4799
+ jobs: {
4800
+ daily_cleanup: {
4801
+ schedule: '0 3 * * *', // 3 AM daily
4802
+ description: 'Clean up expired sessions',
4803
+ action: async (database, context) => {
4804
+ const expired = await database.resource('sessions').list({
4805
+ where: { expiresAt: { $lt: new Date() } }
4806
+ });
4807
+
4808
+ for (const session of expired) {
4809
+ await database.resource('sessions').delete(session.id);
4810
+ }
4811
+
4812
+ return { deleted: expired.length };
4813
+ },
4814
+ enabled: true,
4815
+ retries: 2,
4816
+ timeout: 30000
4817
+ },
4818
+
4819
+ hourly_metrics: {
4820
+ schedule: '@hourly',
4821
+ description: 'Collect system metrics',
4822
+ action: async (database) => {
4823
+ const metrics = {
4824
+ timestamp: new Date().toISOString(),
4825
+ memory: process.memoryUsage(),
4826
+ uptime: process.uptime()
4827
+ };
4828
+
4829
+ await database.resource('metrics').insert({
4830
+ id: `metrics_${Date.now()}`,
4831
+ ...metrics
4832
+ });
4833
+
4834
+ return metrics;
4835
+ }
4836
+ }
4837
+ },
4838
+ onJobComplete: (jobName, result, duration) => {
4839
+ console.log(`Job ${jobName} completed in ${duration}ms`);
4840
+ }
4841
+ })
4842
+ ]
4843
+ });
4844
+
4845
+ await s3db.connect();
4846
+
4847
+ // Jobs run automatically based on schedule
4848
+ // Manual execution
4849
+ await s3db.plugins.scheduler.runJob('daily_cleanup');
4850
+
4851
+ // Get job status
4852
+ const allJobs = s3db.plugins.scheduler.getAllJobsStatus();
4853
+ console.log('Scheduled jobs:', allJobs.length);
4854
+ ```
4855
+
4856
+ ### ⚙️ Configuration Parameters
4857
+
4858
+ | Parameter | Type | Default | Description |
4859
+ |-----------|------|---------|-------------|
4860
+ | `timezone` | string | `'UTC'` | IANA timezone identifier |
4861
+ | `jobs` | object | `{}` | Job definitions |
4862
+ | `defaultTimeout` | number | `60000` | Default job timeout (ms) |
4863
+ | `defaultRetries` | number | `1` | Default retry attempts |
4864
+ | `persistJobs` | boolean | `true` | Store job execution history |
4865
+ | `jobHistoryResource` | string | `'job_history'` | Resource for job history |
4866
+ | `onJobStart` | function | `null` | Callback when job starts |
4867
+ | `onJobComplete` | function | `null` | Callback when job completes |
4868
+ | `onJobError` | function | `null` | Callback when job fails |
4869
+ | `verbose` | boolean | `false` | Enable detailed logging |
4870
+
4871
+ ### Job Configuration
4872
+
4873
+ ```javascript
4874
+ jobs: {
4875
+ job_name: {
4876
+ schedule: '0 0 * * *', // Cron expression (required)
4877
+ description: 'Job description', // Human-readable description
4878
+ action: async (database, context, schedulerPlugin) => {
4879
+ // Job implementation (required)
4880
+ return { success: true };
4881
+ },
4882
+ enabled: true, // Enable/disable job
4883
+ retries: 2, // Retry attempts on failure
4884
+ timeout: 30000, // Timeout in milliseconds
4885
+ meta: { priority: 'high' } // Custom metadata
4886
+ }
4887
+ }
4888
+ ```
4889
+
4890
+ ### Cron Expressions
4891
+
4892
+ #### Standard Format
4893
+ ```
4894
+ * * * * *
4895
+ │ │ │ │ │
4896
+ │ │ │ │ └─── Day of week (0-7, Sunday = 0 or 7)
4897
+ │ │ │ └───── Month (1-12)
4898
+ │ │ └─────── Day of month (1-31)
4899
+ │ └───────── Hour (0-23)
4900
+ └─────────── Minute (0-59)
4901
+ ```
4902
+
4903
+ #### Examples
4904
+ ```javascript
4905
+ '0 0 * * *' // Daily at midnight
4906
+ '0 9 * * MON' // Every Monday at 9 AM
4907
+ '*/15 * * * *' // Every 15 minutes
4908
+ '0 2 1 * *' // First day of month at 2 AM
4909
+ ```
4910
+
4911
+ #### Shorthand Expressions
4912
+ ```javascript
4913
+ '@yearly' // Once a year at midnight on January 1st
4914
+ '@monthly' // Once a month at midnight on the 1st
4915
+ '@weekly' // Once a week at midnight on Sunday
4916
+ '@daily' // Once a day at midnight
4917
+ '@hourly' // Once an hour at the beginning of the hour
4918
+ ```
4919
+
4920
+ ### API Methods
4921
+
4922
+ ```javascript
4923
+ // Job execution
4924
+ const result = await scheduler.runJob(jobName, context);
4925
+ const stats = scheduler.getJobStatus(jobName);
4926
+ const allJobs = scheduler.getAllJobsStatus();
4927
+
4928
+ // Job management
4929
+ scheduler.enableJob(jobName);
4930
+ scheduler.disableJob(jobName);
4931
+ scheduler.addJob(jobName, jobConfig);
4932
+ scheduler.removeJob(jobName);
4933
+
4934
+ // History and monitoring
4935
+ const history = await scheduler.getJobHistory(jobName, { status: 'success', limit: 10 });
4936
+ const stats = scheduler.getJobStatistics(jobName);
4937
+ ```
4938
+
4939
+ ### Events
4940
+
4941
+ ```javascript
4942
+ scheduler.on('job_start', ({ jobName, context }) => {
4943
+ console.log(`Job ${jobName} started`);
4944
+ });
4945
+
4946
+ scheduler.on('job_complete', ({ jobName, result, duration }) => {
4947
+ console.log(`Job ${jobName} completed in ${duration}ms`);
4948
+ });
4949
+
4950
+ scheduler.on('job_error', ({ jobName, error, retryCount }) => {
4951
+ console.error(`Job ${jobName} failed (attempt ${retryCount}):`, error);
4952
+ });
4953
+
4954
+ scheduler.on('job_enabled', ({ jobName }) => {
4955
+ console.log(`Job ${jobName} enabled`);
4956
+ });
4957
+ ```
4958
+
4959
+ ### Integration with Other Plugins
4960
+
4961
+ ```javascript
4962
+ // Scheduled backups
4963
+ jobs: {
4964
+ daily_backup: {
4965
+ schedule: '0 1 * * *',
4966
+ action: async (database) => {
4967
+ const backup = database.getPlugin('BackupPlugin');
4968
+ return await backup.backup('full');
4969
+ }
4970
+ }
4971
+ }
4972
+
4973
+ // Process state machine entities
4974
+ jobs: {
4975
+ process_pending_orders: {
4976
+ schedule: '*/10 * * * *',
4977
+ action: async (database) => {
4978
+ const stateMachine = database.getPlugin('StateMachinePlugin');
4979
+ const orders = await database.resource('orders').list({
4980
+ where: { status: 'pending' }
4981
+ });
4982
+
4983
+ for (const order of orders) {
4984
+ await stateMachine.send('order_processing', order.id, 'AUTO_PROCESS');
4985
+ }
4986
+
4987
+ return { processed: orders.length };
4988
+ }
4989
+ }
4990
+ }
4991
+ ```
4992
+
4993
+ ---
4994
+
4146
4995
  ## 🎯 Best Practices
4147
4996
 
4148
4997
  ### Plugin Performance
@@ -4152,6 +5001,9 @@ const s3db = new S3db({
4152
5001
  3. **Use appropriate sampling** for metrics collection
4153
5002
  4. **Configure retention policies** for audit logs
4154
5003
  5. **Test replicator connections** before deployment
5004
+ 6. **Design efficient state machines** with minimal guards and actions
5005
+ 7. **Schedule backups during low-traffic periods** to minimize impact
5006
+ 8. **Use appropriate job timeouts** to prevent resource exhaustion
4155
5007
 
4156
5008
  ### Plugin Security
4157
5009
 
@@ -4160,6 +5012,9 @@ const s3db = new S3db({
4160
5012
  3. **Use IAM roles** instead of access keys when possible
4161
5013
  4. **Encrypt replication data** in transit and at rest
4162
5014
  5. **Validate message sources** in queue consumers
5015
+ 6. **Secure state machine actions** to prevent unauthorized transitions
5016
+ 7. **Encrypt backup data** for sensitive databases
5017
+ 8. **Restrict job execution permissions** to necessary resources only
4163
5018
 
4164
5019
  ### Plugin Monitoring
4165
5020
 
@@ -4168,6 +5023,9 @@ const s3db = new S3db({
4168
5023
  3. **Track error rates** across all plugins
4169
5024
  4. **Use structured logging** for debugging
4170
5025
  5. **Implement circuit breakers** for external services
5026
+ 6. **Monitor state machine transition rates** and error patterns
5027
+ 7. **Track backup success rates** and storage usage
5028
+ 8. **Alert on job failures** and execution delays
4171
5029
 
4172
5030
  ---
4173
5031