@weave-apps/sdk 0.1.12 → 0.1.14
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/README.md +90 -0
- package/package.json +1 -1
- package/templates/WEAVE_SPEC.md +265 -3
package/README.md
CHANGED
|
@@ -12,6 +12,7 @@ Official SDK for building third-party applications for the Weave Platform.
|
|
|
12
12
|
- ✅ **Shadow DOM Isolation** - Scoped styles and encapsulation
|
|
13
13
|
- ✅ **Background Services** - Run code without user interaction
|
|
14
14
|
- ✅ **State Persistence** - Survive page reloads with auto-persist
|
|
15
|
+
- ✅ **Scheduled Tasks** - Cron jobs with standard cron syntax
|
|
15
16
|
- ✅ **Multi-Page Flows** - Pending operations across navigations
|
|
16
17
|
- ✅ **Form Integration** - Auto-fill forms with extracted data
|
|
17
18
|
- ✅ **AI Integration** - Leverage AI for smart form filling
|
|
@@ -58,6 +59,9 @@ Official SDK for building third-party applications for the Weave Platform.
|
|
|
58
59
|
- [Auto-Persist (Recommended)](#auto-persist-recommended)
|
|
59
60
|
- [Multi-Page Flows (Pending Operations)](#multi-page-flows-pending-operations)
|
|
60
61
|
- [State TTL](#state-ttl)
|
|
62
|
+
- [Scheduled Tasks (Cron Jobs)](#scheduled-tasks-cron-jobs)
|
|
63
|
+
- [🔮 Secret Hack: Persistent Cron](#-secret-hack-persistent-cron)
|
|
64
|
+
- [Cron Syntax](#cron-syntax)
|
|
61
65
|
- [Settings & Configuration](#settings--configuration)
|
|
62
66
|
- [Error Handling](#error-handling)
|
|
63
67
|
- [Performance Tips](#performance-tips)
|
|
@@ -540,6 +544,92 @@ class DataTransferApp extends WeaveBaseApp {
|
|
|
540
544
|
|
|
541
545
|
Persisted state expires after **5 minutes** by default. This prevents stale state from accumulating.
|
|
542
546
|
|
|
547
|
+
### Scheduled Tasks (Cron Jobs)
|
|
548
|
+
|
|
549
|
+
Apps can register scheduled tasks using standard cron syntax. The browser extension acts as the master clock.
|
|
550
|
+
|
|
551
|
+
```typescript
|
|
552
|
+
class PollingApp extends WeaveBaseApp {
|
|
553
|
+
constructor() {
|
|
554
|
+
super({
|
|
555
|
+
id: 'polling-app',
|
|
556
|
+
name: 'Polling App',
|
|
557
|
+
version: '1.0.0',
|
|
558
|
+
category: 'utility',
|
|
559
|
+
description: 'App with scheduled polling',
|
|
560
|
+
author: 'Your Name',
|
|
561
|
+
persistState: true, // Important for cron!
|
|
562
|
+
});
|
|
563
|
+
|
|
564
|
+
this.state = {
|
|
565
|
+
cronEnabled: false, // Track cron state
|
|
566
|
+
tickCount: 0
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
async onBackgroundService() {
|
|
571
|
+
// Re-register cron if it was enabled before page reload
|
|
572
|
+
if (this.state.cronEnabled) {
|
|
573
|
+
await this.startPolling();
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
async startPolling() {
|
|
578
|
+
// Register cron job - every 5 seconds
|
|
579
|
+
const jobId = await this.cronTab('*/5 * * * * *', this.handleTick, 'poller');
|
|
580
|
+
if (jobId) {
|
|
581
|
+
this.setState({ cronEnabled: true });
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
async stopPolling() {
|
|
586
|
+
await this.cronUnregisterAll();
|
|
587
|
+
this.setState({ cronEnabled: false });
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
handleTick() {
|
|
591
|
+
this.setState({ tickCount: this.state.tickCount + 1 });
|
|
592
|
+
console.log('Tick!', this.state.tickCount);
|
|
593
|
+
|
|
594
|
+
// Update UI if app is open
|
|
595
|
+
if (this.isConnected) {
|
|
596
|
+
this.render();
|
|
597
|
+
this.setupEventListeners();
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
```
|
|
602
|
+
|
|
603
|
+
#### 🔮 Secret Hack: Persistent Cron
|
|
604
|
+
|
|
605
|
+
Cron jobs don't survive page reloads by default. The **secret hack** is to combine `persistState: true` with a `cronEnabled` state flag:
|
|
606
|
+
|
|
607
|
+
1. **Track cron state** - Add `cronEnabled: boolean` to your state
|
|
608
|
+
2. **Set flag when starting** - `this.setState({ cronEnabled: true })`
|
|
609
|
+
3. **Re-register on reload** - Check `this.state.cronEnabled` in `onBackgroundService()`
|
|
610
|
+
|
|
611
|
+
This way, when the page reloads, your state is restored (including `cronEnabled: true`), and `onBackgroundService()` automatically re-registers the cron job!
|
|
612
|
+
|
|
613
|
+
#### Cron Syntax
|
|
614
|
+
|
|
615
|
+
```
|
|
616
|
+
┌───────────── second (0-59) - optional
|
|
617
|
+
│ ┌───────────── minute (0-59)
|
|
618
|
+
│ │ ┌───────────── hour (0-23)
|
|
619
|
+
│ │ │ ┌───────────── day of month (1-31)
|
|
620
|
+
│ │ │ │ ┌───────────── month (1-12)
|
|
621
|
+
│ │ │ │ │ ┌───────────── day of week (0-6)
|
|
622
|
+
│ │ │ │ │ │
|
|
623
|
+
* * * * * *
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
**Common patterns:**
|
|
627
|
+
- `* * * * * *` - Every second
|
|
628
|
+
- `*/5 * * * * *` - Every 5 seconds
|
|
629
|
+
- `*/30 * * * * *` - Every 30 seconds
|
|
630
|
+
- `0 * * * * *` - Every minute
|
|
631
|
+
- `0 */5 * * * *` - Every 5 minutes
|
|
632
|
+
|
|
543
633
|
### Settings & Configuration
|
|
544
634
|
|
|
545
635
|
Settings are injected from the Enterprise Console and displayed as auto-extracted form fields:
|
package/package.json
CHANGED
package/templates/WEAVE_SPEC.md
CHANGED
|
@@ -1088,9 +1088,10 @@ customElements.define('smart-form-assistant', SmartFormAssistant);
|
|
|
1088
1088
|
4. **Multi-Page Flows**: Use `this.background?.setPendingOperation()` for cross-page operations
|
|
1089
1089
|
5. **Background Service**: `onBackgroundService()` runs immediately, before DOM attachment
|
|
1090
1090
|
6. **URL Monitoring**: `onUrlChange()` detects SPA navigation automatically
|
|
1091
|
-
7. **
|
|
1092
|
-
8. **
|
|
1093
|
-
9. **
|
|
1091
|
+
7. **Scheduled Tasks**: Use `this.cronTab()` to register cron jobs with standard cron syntax
|
|
1092
|
+
8. **Shared Context**: Background and foreground share the same instance and state
|
|
1093
|
+
9. **DOM Check**: Use `this.isConnected` to check if app is attached to DOM
|
|
1094
|
+
10. **No User Interaction Required**: Apps can run and inject UI automatically
|
|
1094
1095
|
|
|
1095
1096
|
### Helper Methods (Available in `this`)
|
|
1096
1097
|
|
|
@@ -1118,6 +1119,18 @@ this.shadowRoot: ShadowRoot
|
|
|
1118
1119
|
|
|
1119
1120
|
// Access background API for state persistence
|
|
1120
1121
|
this.background: WeaveBackgroundAPI | null
|
|
1122
|
+
|
|
1123
|
+
// Access cron API for scheduled tasks
|
|
1124
|
+
this.cron: WeaveCronAPI | null
|
|
1125
|
+
|
|
1126
|
+
// Register a cron job (shorthand)
|
|
1127
|
+
await this.cronTab(expression: string, callback: () => void, jobName?: string): Promise<string | null>
|
|
1128
|
+
|
|
1129
|
+
// Unregister a cron job by name
|
|
1130
|
+
await this.cronUnregister(jobName: string): Promise<boolean>
|
|
1131
|
+
|
|
1132
|
+
// Unregister all cron jobs for this app
|
|
1133
|
+
await this.cronUnregisterAll(): Promise<number>
|
|
1121
1134
|
```
|
|
1122
1135
|
|
|
1123
1136
|
## State Persistence (Survive Page Reloads)
|
|
@@ -1372,6 +1385,255 @@ For long-term persistence, use `this.weaveAPI.appData.*` methods instead.
|
|
|
1372
1385
|
- Don't forget to clear pending operations
|
|
1373
1386
|
- Don't assume state will persist forever (5 min TTL)
|
|
1374
1387
|
|
|
1388
|
+
## Scheduled Tasks (Cron Service)
|
|
1389
|
+
|
|
1390
|
+
### Overview
|
|
1391
|
+
|
|
1392
|
+
Apps can register **scheduled tasks** that run on a timer using standard cron syntax. The browser extension acts as the master clock, ticking every second and notifying apps when their cron expressions match.
|
|
1393
|
+
|
|
1394
|
+
**Use cases:**
|
|
1395
|
+
- ⏰ **Periodic polling** - Check for updates every N seconds
|
|
1396
|
+
- 🔄 **Auto-refresh** - Update UI or data at intervals
|
|
1397
|
+
- 📊 **Monitoring** - Track metrics over time
|
|
1398
|
+
- 🔔 **Reminders** - Trigger notifications on schedule
|
|
1399
|
+
|
|
1400
|
+
### Architecture
|
|
1401
|
+
|
|
1402
|
+
```
|
|
1403
|
+
[Background Script: CronService] ← Master clock (ticks every second)
|
|
1404
|
+
↓
|
|
1405
|
+
[Content Script: CronBridge] ← Routes tick messages
|
|
1406
|
+
↓
|
|
1407
|
+
[Iframe: App] ← Receives CRON_TICK, executes callback
|
|
1408
|
+
```
|
|
1409
|
+
|
|
1410
|
+
### Registering a Cron Job
|
|
1411
|
+
|
|
1412
|
+
Use `this.cronTab()` to register a cron job:
|
|
1413
|
+
|
|
1414
|
+
```typescript
|
|
1415
|
+
class MyApp extends WeaveBaseApp {
|
|
1416
|
+
constructor() {
|
|
1417
|
+
super({
|
|
1418
|
+
id: 'my-app',
|
|
1419
|
+
name: 'My App',
|
|
1420
|
+
version: '1.0.0',
|
|
1421
|
+
category: 'utility',
|
|
1422
|
+
description: 'App with scheduled tasks',
|
|
1423
|
+
tags: ['cron'],
|
|
1424
|
+
persistState: true, // Recommended for cron apps
|
|
1425
|
+
});
|
|
1426
|
+
|
|
1427
|
+
this.state = {
|
|
1428
|
+
tickCount: 0,
|
|
1429
|
+
cronEnabled: false
|
|
1430
|
+
};
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1433
|
+
async onBackgroundService() {
|
|
1434
|
+
// Re-register cron if it was enabled before page reload
|
|
1435
|
+
if (this.state.cronEnabled) {
|
|
1436
|
+
await this.startCron();
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1440
|
+
async startCron() {
|
|
1441
|
+
// Register a cron job - every 5 seconds
|
|
1442
|
+
const jobId = await this.cronTab('*/5 * * * * *', this.handleTick, 'myTicker');
|
|
1443
|
+
|
|
1444
|
+
if (jobId) {
|
|
1445
|
+
console.log('Cron registered:', jobId);
|
|
1446
|
+
this.setState({ cronEnabled: true });
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
|
|
1450
|
+
async stopCron() {
|
|
1451
|
+
await this.cronUnregisterAll();
|
|
1452
|
+
this.setState({ cronEnabled: false });
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
// Cron callback - called every 5 seconds
|
|
1456
|
+
handleTick() {
|
|
1457
|
+
this.setState({ tickCount: this.state.tickCount + 1 });
|
|
1458
|
+
console.log('Tick!', this.state.tickCount);
|
|
1459
|
+
|
|
1460
|
+
// Update UI if app is open
|
|
1461
|
+
if (this.isConnected) {
|
|
1462
|
+
this.render();
|
|
1463
|
+
this.setupEventListeners();
|
|
1464
|
+
}
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
```
|
|
1468
|
+
|
|
1469
|
+
### Cron Syntax
|
|
1470
|
+
|
|
1471
|
+
The cron service supports both **5-field** (standard) and **6-field** (with seconds) expressions:
|
|
1472
|
+
|
|
1473
|
+
#### 5-Field (Standard Cron)
|
|
1474
|
+
```
|
|
1475
|
+
┌───────────── minute (0-59)
|
|
1476
|
+
│ ┌───────────── hour (0-23)
|
|
1477
|
+
│ │ ┌───────────── day of month (1-31)
|
|
1478
|
+
│ │ │ ┌───────────── month (1-12)
|
|
1479
|
+
│ │ │ │ ┌───────────── day of week (0-6, Sunday=0)
|
|
1480
|
+
│ │ │ │ │
|
|
1481
|
+
* * * * *
|
|
1482
|
+
```
|
|
1483
|
+
|
|
1484
|
+
#### 6-Field (With Seconds)
|
|
1485
|
+
```
|
|
1486
|
+
┌───────────── second (0-59)
|
|
1487
|
+
│ ┌───────────── minute (0-59)
|
|
1488
|
+
│ │ ┌───────────── hour (0-23)
|
|
1489
|
+
│ │ │ ┌───────────── day of month (1-31)
|
|
1490
|
+
│ │ │ │ ┌───────────── month (1-12)
|
|
1491
|
+
│ │ │ │ │ ┌───────────── day of week (0-6, Sunday=0)
|
|
1492
|
+
│ │ │ │ │ │
|
|
1493
|
+
* * * * * *
|
|
1494
|
+
```
|
|
1495
|
+
|
|
1496
|
+
#### Special Characters
|
|
1497
|
+
|
|
1498
|
+
| Character | Description | Example |
|
|
1499
|
+
|-----------|-------------|---------|
|
|
1500
|
+
| `*` | Any value | `* * * * * *` = every second |
|
|
1501
|
+
| `,` | Value list | `0,30 * * * * *` = at 0 and 30 seconds |
|
|
1502
|
+
| `-` | Range | `0-10 * * * * *` = seconds 0-10 |
|
|
1503
|
+
| `/` | Step | `*/5 * * * * *` = every 5 seconds |
|
|
1504
|
+
|
|
1505
|
+
#### Common Examples
|
|
1506
|
+
|
|
1507
|
+
```typescript
|
|
1508
|
+
// Every second
|
|
1509
|
+
await this.cronTab('* * * * * *', callback);
|
|
1510
|
+
|
|
1511
|
+
// Every 5 seconds
|
|
1512
|
+
await this.cronTab('*/5 * * * * *', callback);
|
|
1513
|
+
|
|
1514
|
+
// Every 10 seconds
|
|
1515
|
+
await this.cronTab('*/10 * * * * *', callback);
|
|
1516
|
+
|
|
1517
|
+
// Every 30 seconds
|
|
1518
|
+
await this.cronTab('0,30 * * * * *', callback);
|
|
1519
|
+
|
|
1520
|
+
// Every minute (at second 0)
|
|
1521
|
+
await this.cronTab('0 * * * * *', callback);
|
|
1522
|
+
|
|
1523
|
+
// Every 5 minutes
|
|
1524
|
+
await this.cronTab('0 */5 * * * *', callback);
|
|
1525
|
+
|
|
1526
|
+
// Every hour at minute 0
|
|
1527
|
+
await this.cronTab('0 0 * * * *', callback);
|
|
1528
|
+
|
|
1529
|
+
// Standard 5-field: every minute
|
|
1530
|
+
await this.cronTab('* * * * *', callback);
|
|
1531
|
+
```
|
|
1532
|
+
|
|
1533
|
+
### Cron API Methods
|
|
1534
|
+
|
|
1535
|
+
```typescript
|
|
1536
|
+
// Register a cron job
|
|
1537
|
+
// Returns job ID if successful, null if failed
|
|
1538
|
+
await this.cronTab(
|
|
1539
|
+
cronExpression: string, // Cron expression (5 or 6 fields)
|
|
1540
|
+
callback: () => void, // Function to call on each tick
|
|
1541
|
+
jobName?: string // Optional unique name for the job
|
|
1542
|
+
): Promise<string | null>
|
|
1543
|
+
|
|
1544
|
+
// Unregister a specific job by name
|
|
1545
|
+
await this.cronUnregister(jobName: string): Promise<boolean>
|
|
1546
|
+
|
|
1547
|
+
// Unregister all cron jobs for this app
|
|
1548
|
+
await this.cronUnregisterAll(): Promise<number>
|
|
1549
|
+
|
|
1550
|
+
// Access cron API directly (advanced)
|
|
1551
|
+
this.cron?.register(expression, callback, name)
|
|
1552
|
+
this.cron?.unregister(jobName)
|
|
1553
|
+
this.cron?.unregisterAll()
|
|
1554
|
+
this.cron?.list()
|
|
1555
|
+
```
|
|
1556
|
+
|
|
1557
|
+
### Persisting Cron State Across Page Reloads
|
|
1558
|
+
|
|
1559
|
+
Cron jobs are **not automatically re-registered** after a page reload. Use `persistState: true` and re-register in `onBackgroundService()`:
|
|
1560
|
+
|
|
1561
|
+
```typescript
|
|
1562
|
+
class PersistentCronApp extends WeaveBaseApp {
|
|
1563
|
+
constructor() {
|
|
1564
|
+
super({
|
|
1565
|
+
id: 'persistent-cron',
|
|
1566
|
+
name: 'Persistent Cron',
|
|
1567
|
+
version: '1.0.0',
|
|
1568
|
+
category: 'utility',
|
|
1569
|
+
description: 'Cron that survives page reloads',
|
|
1570
|
+
tags: ['cron'],
|
|
1571
|
+
persistState: true, // ✅ Enable state persistence
|
|
1572
|
+
});
|
|
1573
|
+
|
|
1574
|
+
this.state = {
|
|
1575
|
+
cronEnabled: false,
|
|
1576
|
+
tickCount: 0
|
|
1577
|
+
};
|
|
1578
|
+
}
|
|
1579
|
+
|
|
1580
|
+
async onBackgroundService() {
|
|
1581
|
+
// ✅ Re-register cron if it was enabled before reload
|
|
1582
|
+
if (this.state.cronEnabled) {
|
|
1583
|
+
await this.cronTab('*/5 * * * * *', this.handleTick, 'ticker');
|
|
1584
|
+
}
|
|
1585
|
+
}
|
|
1586
|
+
|
|
1587
|
+
handleTick() {
|
|
1588
|
+
this.setState({ tickCount: this.state.tickCount + 1 });
|
|
1589
|
+
}
|
|
1590
|
+
|
|
1591
|
+
async toggleCron() {
|
|
1592
|
+
if (this.state.cronEnabled) {
|
|
1593
|
+
await this.cronUnregisterAll();
|
|
1594
|
+
this.setState({ cronEnabled: false });
|
|
1595
|
+
} else {
|
|
1596
|
+
await this.cronTab('*/5 * * * * *', this.handleTick, 'ticker');
|
|
1597
|
+
this.setState({ cronEnabled: true });
|
|
1598
|
+
}
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
```
|
|
1602
|
+
|
|
1603
|
+
### Best Practices
|
|
1604
|
+
|
|
1605
|
+
#### ✅ DO:
|
|
1606
|
+
- Use `persistState: true` to remember cron state across reloads
|
|
1607
|
+
- Re-register cron jobs in `onBackgroundService()` if they were enabled
|
|
1608
|
+
- Give jobs meaningful names for easier management
|
|
1609
|
+
- Use appropriate intervals (don't poll every second unless necessary)
|
|
1610
|
+
- Update UI only if `this.isConnected` (app is open)
|
|
1611
|
+
- Clean up cron jobs in `cleanup()` method
|
|
1612
|
+
|
|
1613
|
+
#### ❌ DON'T:
|
|
1614
|
+
- Don't register cron jobs in the constructor (use `onBackgroundService()`)
|
|
1615
|
+
- Don't use very short intervals without good reason (battery/performance)
|
|
1616
|
+
- Don't assume cron jobs survive page reloads (they don't)
|
|
1617
|
+
- Don't forget to unregister jobs when no longer needed
|
|
1618
|
+
|
|
1619
|
+
### Cleanup
|
|
1620
|
+
|
|
1621
|
+
Cron jobs are automatically cleaned up when:
|
|
1622
|
+
- The tab is closed
|
|
1623
|
+
- The app explicitly unregisters them
|
|
1624
|
+
- The extension is reloaded
|
|
1625
|
+
|
|
1626
|
+
For manual cleanup:
|
|
1627
|
+
|
|
1628
|
+
```typescript
|
|
1629
|
+
class MyApp extends WeaveBaseApp {
|
|
1630
|
+
protected cleanup(): void {
|
|
1631
|
+
// Clean up cron jobs when app is removed from DOM
|
|
1632
|
+
this.cronUnregisterAll();
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1635
|
+
```
|
|
1636
|
+
|
|
1375
1637
|
## Weave Backend API
|
|
1376
1638
|
|
|
1377
1639
|
### ⚠️ CRITICAL: API Access Restrictions
|