@wealthfolio/addon-sdk 1.0.0 → 2.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.
- package/CHANGELOG.md +19 -8
- package/README.md +195 -145
- package/dist/{chunk-3OBZP7TN.mjs → chunk-TB3G7LNW.js} +10 -40
- package/dist/chunk-TB3G7LNW.js.map +1 -0
- package/dist/{index.mjs → index.js} +33 -22
- package/dist/index.js.map +1 -0
- package/dist/{permissions.mjs → permissions.js} +2 -2
- package/dist/src/data-types.d.ts +513 -0
- package/dist/src/host-api.d.ts +556 -0
- package/dist/src/index.d.ts +28 -0
- package/dist/src/manifest.d.ts +176 -0
- package/dist/{permissions.d.mts → src/permissions.d.ts} +16 -18
- package/dist/src/query-keys.d.ts +44 -0
- package/dist/src/types.d.ts +88 -0
- package/dist/src/utils.d.ts +24 -0
- package/dist/src/version.d.ts +4 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/types.js +1 -0
- package/package.json +26 -16
- package/dist/chunk-3OBZP7TN.mjs.map +0 -1
- package/dist/index.d.mts +0 -279
- package/dist/index.mjs.map +0 -1
- package/dist/types-CxtChQdm.d.mts +0 -1137
- package/dist/types.d.mts +0 -2
- package/dist/types.mjs +0 -1
- /package/dist/{permissions.mjs.map → permissions.js.map} +0 -0
- /package/dist/{types.mjs.map → types.js.map} +0 -0
package/README.md
CHANGED
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
[](https://www.typescriptlang.org/)
|
|
7
7
|
[](https://nodejs.org/)
|
|
8
8
|
|
|
9
|
-
A comprehensive TypeScript SDK for building secure, feature-rich addons for
|
|
9
|
+
A comprehensive TypeScript SDK for building secure, feature-rich addons for
|
|
10
|
+
Wealthfolio. Extend your portfolio management experience with custom analytics,
|
|
11
|
+
integrations, and visualizations.
|
|
10
12
|
|
|
11
13
|
## 📚 Table of Contents
|
|
12
14
|
|
|
@@ -30,8 +32,9 @@ A comprehensive TypeScript SDK for building secure, feature-rich addons for Weal
|
|
|
30
32
|
|
|
31
33
|
## 🚀 Features
|
|
32
34
|
|
|
33
|
-
- **Type-Safe Development**: Full TypeScript support with comprehensive type
|
|
34
|
-
|
|
35
|
+
- **Type-Safe Development**: Full TypeScript support with comprehensive type
|
|
36
|
+
definitions
|
|
37
|
+
- **Security-First**: Built-in permission system with granular risk assessment
|
|
35
38
|
- **Modular Architecture**: Clean separation of concerns with well-defined APIs
|
|
36
39
|
- **React Integration**: Seamless integration with React components and hooks
|
|
37
40
|
- **Hot Reloading**: Development-friendly with automatic reload capabilities
|
|
@@ -75,13 +78,13 @@ export default function enable(context: AddonContext) {
|
|
|
75
78
|
id: 'my-addon',
|
|
76
79
|
label: 'My Addon',
|
|
77
80
|
icon: 'chart-line',
|
|
78
|
-
route: '/addons/my-addon'
|
|
81
|
+
route: '/addons/my-addon',
|
|
79
82
|
});
|
|
80
83
|
|
|
81
84
|
// Register route
|
|
82
85
|
context.router.add({
|
|
83
86
|
path: '/addons/my-addon',
|
|
84
|
-
component: () => import('./MyComponent')
|
|
87
|
+
component: () => import('./MyComponent'),
|
|
85
88
|
});
|
|
86
89
|
|
|
87
90
|
// Log activation
|
|
@@ -202,32 +205,33 @@ Create a `manifest.json` file in your addon root:
|
|
|
202
205
|
|
|
203
206
|
### Required Fields
|
|
204
207
|
|
|
205
|
-
| Field
|
|
206
|
-
|
|
207
|
-
| `id`
|
|
208
|
-
| `name`
|
|
209
|
-
| `version` | `string` | Semantic version (e.g., "1.0.0")
|
|
208
|
+
| Field | Type | Description |
|
|
209
|
+
| --------- | -------- | ---------------------------------------------- |
|
|
210
|
+
| `id` | `string` | Unique identifier (lowercase, hyphens allowed) |
|
|
211
|
+
| `name` | `string` | Human-readable addon name |
|
|
212
|
+
| `version` | `string` | Semantic version (e.g., "1.0.0") |
|
|
210
213
|
|
|
211
214
|
### Optional Fields
|
|
212
215
|
|
|
213
|
-
| Field
|
|
214
|
-
|
|
215
|
-
| `description`
|
|
216
|
-
| `author`
|
|
217
|
-
| `homepage`
|
|
218
|
-
| `license`
|
|
219
|
-
| `main`
|
|
220
|
-
| `sdkVersion`
|
|
221
|
-
| `permissions`
|
|
222
|
-
| `minWealthfolioVersion` | `string`
|
|
223
|
-
| `keywords`
|
|
224
|
-
| `icon`
|
|
216
|
+
| Field | Type | Description |
|
|
217
|
+
| ----------------------- | -------------- | -------------------------------------- |
|
|
218
|
+
| `description` | `string` | Brief description of functionality |
|
|
219
|
+
| `author` | `string` | Author name or organization |
|
|
220
|
+
| `homepage` | `string` | Project homepage URL |
|
|
221
|
+
| `license` | `string` | License identifier |
|
|
222
|
+
| `main` | `string` | Entry point file (default: "addon.js") |
|
|
223
|
+
| `sdkVersion` | `string` | Compatible SDK version |
|
|
224
|
+
| `permissions` | `Permission[]` | Security permissions required |
|
|
225
|
+
| `minWealthfolioVersion` | `string` | Minimum Wealthfolio version required |
|
|
226
|
+
| `keywords` | `string[]` | Keywords for discoverability |
|
|
227
|
+
| `icon` | `string` | Addon icon (base64 or relative path) |
|
|
225
228
|
|
|
226
229
|
## 🔨 Development Guide
|
|
227
230
|
|
|
228
231
|
### Modern Addon Example
|
|
229
232
|
|
|
230
|
-
Based on the current SDK architecture, here's a complete real-world addon
|
|
233
|
+
Based on the current SDK architecture, here's a complete real-world addon
|
|
234
|
+
example:
|
|
231
235
|
|
|
232
236
|
```typescript
|
|
233
237
|
// src/addon.tsx
|
|
@@ -263,7 +267,7 @@ const enable: AddonEnableFunction = (context) => {
|
|
|
263
267
|
order: 200
|
|
264
268
|
});
|
|
265
269
|
addedItems.push(sidebarItem);
|
|
266
|
-
|
|
270
|
+
|
|
267
271
|
context.api.logger.debug('Sidebar navigation item added successfully');
|
|
268
272
|
|
|
269
273
|
// Create wrapper component with shared QueryClient
|
|
@@ -279,11 +283,11 @@ const enable: AddonEnableFunction = (context) => {
|
|
|
279
283
|
// Register route with lazy loading
|
|
280
284
|
context.router.add({
|
|
281
285
|
path: '/addons/investment-fees-tracker',
|
|
282
|
-
component: React.lazy(() => Promise.resolve({
|
|
283
|
-
default: InvestmentFeesTrackerWrapper
|
|
286
|
+
component: React.lazy(() => Promise.resolve({
|
|
287
|
+
default: InvestmentFeesTrackerWrapper
|
|
284
288
|
}))
|
|
285
289
|
});
|
|
286
|
-
|
|
290
|
+
|
|
287
291
|
context.api.logger.debug('Route registered successfully');
|
|
288
292
|
context.api.logger.info('Investment Fees Tracker addon enabled successfully');
|
|
289
293
|
|
|
@@ -295,7 +299,7 @@ const enable: AddonEnableFunction = (context) => {
|
|
|
295
299
|
// Register cleanup callback
|
|
296
300
|
context.onDisable(() => {
|
|
297
301
|
context.api.logger.info('🛑 Investment Fees Tracker addon is being disabled');
|
|
298
|
-
|
|
302
|
+
|
|
299
303
|
// Remove all sidebar items
|
|
300
304
|
addedItems.forEach(item => {
|
|
301
305
|
try {
|
|
@@ -304,7 +308,7 @@ const enable: AddonEnableFunction = (context) => {
|
|
|
304
308
|
context.api.logger.error('Error removing sidebar item: ' + (error as Error).message);
|
|
305
309
|
}
|
|
306
310
|
});
|
|
307
|
-
|
|
311
|
+
|
|
308
312
|
context.api.logger.info('Investment Fees Tracker addon disabled successfully');
|
|
309
313
|
});
|
|
310
314
|
};
|
|
@@ -315,13 +319,15 @@ export default enable;
|
|
|
315
319
|
|
|
316
320
|
### Key Features Demonstrated
|
|
317
321
|
|
|
318
|
-
1. **Shared Query Client**: Uses `context.api.query.getClient()` for consistent
|
|
322
|
+
1. **Shared Query Client**: Uses `context.api.query.getClient()` for consistent
|
|
323
|
+
data fetching
|
|
319
324
|
2. **UI Icons**: Leverages `@wealthfolio/ui` for consistent iconography
|
|
320
325
|
3. **Error Handling**: Comprehensive error handling with logging
|
|
321
326
|
4. **Resource Management**: Proper cleanup of sidebar items and event listeners
|
|
322
327
|
5. **TypeScript**: Full type safety with proper imports
|
|
323
328
|
6. **Lazy Loading**: Efficient component loading with React.lazy
|
|
324
|
-
|
|
329
|
+
|
|
330
|
+
````
|
|
325
331
|
|
|
326
332
|
### Advanced Component Example
|
|
327
333
|
|
|
@@ -366,7 +372,7 @@ export function FeesPage({ ctx }: FeesPageProps) {
|
|
|
366
372
|
// Calculate total fees from activities
|
|
367
373
|
const totalFees = React.useMemo(() => {
|
|
368
374
|
if (!activities?.data) return 0;
|
|
369
|
-
|
|
375
|
+
|
|
370
376
|
return activities.data.reduce((total, activity) => {
|
|
371
377
|
// Look for fee-related activities or transaction costs
|
|
372
378
|
const fee = activity.fee || 0;
|
|
@@ -376,11 +382,11 @@ export function FeesPage({ ctx }: FeesPageProps) {
|
|
|
376
382
|
|
|
377
383
|
useEffect(() => {
|
|
378
384
|
if (!isLoading) {
|
|
379
|
-
ctx.api.logger.info('Fees data loaded successfully', {
|
|
385
|
+
ctx.api.logger.info('Fees data loaded successfully', {
|
|
380
386
|
accountsCount: accounts?.length,
|
|
381
387
|
holdingsCount: holdings?.length,
|
|
382
388
|
activitiesCount: activities?.data?.length,
|
|
383
|
-
totalFees
|
|
389
|
+
totalFees
|
|
384
390
|
});
|
|
385
391
|
}
|
|
386
392
|
}, [isLoading, accounts, holdings, activities, totalFees, ctx.api.logger]);
|
|
@@ -402,7 +408,7 @@ export function FeesPage({ ctx }: FeesPageProps) {
|
|
|
402
408
|
<h1 className="text-3xl font-bold text-gray-900 mb-2">Investment Fees Tracker</h1>
|
|
403
409
|
<p className="text-gray-600">Track and analyze fees across your investment portfolio</p>
|
|
404
410
|
</div>
|
|
405
|
-
|
|
411
|
+
|
|
406
412
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
|
|
407
413
|
<div className="bg-white p-6 rounded-lg shadow border">
|
|
408
414
|
<h3 className="text-lg font-semibold text-gray-900 mb-2">Total Fees Paid</h3>
|
|
@@ -478,7 +484,7 @@ export default FeesPage;
|
|
|
478
484
|
}
|
|
479
485
|
|
|
480
486
|
export default AnalyticsDashboard;
|
|
481
|
-
|
|
487
|
+
````
|
|
482
488
|
|
|
483
489
|
### Using Hooks and State Management
|
|
484
490
|
|
|
@@ -490,7 +496,9 @@ import type { Holding, PerformanceMetrics } from '@wealthfolio/addon-sdk/types';
|
|
|
490
496
|
|
|
491
497
|
export function usePortfolioData(accountId?: string) {
|
|
492
498
|
const [holdings, setHoldings] = useState<Holding[]>([]);
|
|
493
|
-
const [performance, setPerformance] = useState<PerformanceMetrics | null>(
|
|
499
|
+
const [performance, setPerformance] = useState<PerformanceMetrics | null>(
|
|
500
|
+
null,
|
|
501
|
+
);
|
|
494
502
|
const [loading, setLoading] = useState(true);
|
|
495
503
|
const [error, setError] = useState<string | null>(null);
|
|
496
504
|
|
|
@@ -501,15 +509,18 @@ export function usePortfolioData(accountId?: string) {
|
|
|
501
509
|
setError(null);
|
|
502
510
|
|
|
503
511
|
const ctx = getAddonContext();
|
|
504
|
-
|
|
505
|
-
const holdingsData = await ctx.api.portfolio.getHoldings(
|
|
512
|
+
|
|
513
|
+
const holdingsData = await ctx.api.portfolio.getHoldings(
|
|
514
|
+
accountId || '',
|
|
515
|
+
);
|
|
506
516
|
setHoldings(holdingsData);
|
|
507
517
|
|
|
508
518
|
if (accountId) {
|
|
509
|
-
const performanceData =
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
519
|
+
const performanceData =
|
|
520
|
+
await ctx.api.portfolio.calculatePerformanceSummary({
|
|
521
|
+
itemType: 'account',
|
|
522
|
+
itemId: accountId,
|
|
523
|
+
});
|
|
513
524
|
setPerformance(performanceData);
|
|
514
525
|
}
|
|
515
526
|
} catch (err) {
|
|
@@ -530,18 +541,18 @@ export function usePortfolioData(accountId?: string) {
|
|
|
530
541
|
|
|
531
542
|
### Permission Categories
|
|
532
543
|
|
|
533
|
-
| Category
|
|
534
|
-
|
|
535
|
-
| `ui`
|
|
536
|
-
| `market-data`
|
|
537
|
-
| `events`
|
|
538
|
-
| `currency`
|
|
539
|
-
| `portfolio`
|
|
540
|
-
| `files`
|
|
541
|
-
| `financial-planning` | Medium
|
|
542
|
-
| `activities`
|
|
543
|
-
| `accounts`
|
|
544
|
-
| `settings`
|
|
544
|
+
| Category | Risk Level | Description |
|
|
545
|
+
| -------------------- | ---------- | ------------------------------- |
|
|
546
|
+
| `ui` | Low | Add navigation items and routes |
|
|
547
|
+
| `market-data` | Low | Access market prices and quotes |
|
|
548
|
+
| `events` | Low | Listen to application events |
|
|
549
|
+
| `currency` | Low | Access exchange rates |
|
|
550
|
+
| `portfolio` | Medium | Access holdings and valuations |
|
|
551
|
+
| `files` | Medium | File dialog operations |
|
|
552
|
+
| `financial-planning` | Medium | Goals and contribution limits |
|
|
553
|
+
| `activities` | High | Transaction history access |
|
|
554
|
+
| `accounts` | High | Account management |
|
|
555
|
+
| `settings` | High | Application configuration |
|
|
545
556
|
|
|
546
557
|
### Declaring Permissions
|
|
547
558
|
|
|
@@ -585,26 +596,26 @@ export default defineConfig({
|
|
|
585
596
|
entry: resolve(__dirname, 'src/index.ts'),
|
|
586
597
|
name: 'MyPortfolioAddon',
|
|
587
598
|
fileName: 'addon',
|
|
588
|
-
formats: ['es']
|
|
599
|
+
formats: ['es'],
|
|
589
600
|
},
|
|
590
601
|
rollupOptions: {
|
|
591
602
|
external: ['react', 'react-dom'],
|
|
592
603
|
output: {
|
|
593
604
|
globals: {
|
|
594
605
|
react: 'React',
|
|
595
|
-
'react-dom': 'ReactDOM'
|
|
596
|
-
}
|
|
597
|
-
}
|
|
606
|
+
'react-dom': 'ReactDOM',
|
|
607
|
+
},
|
|
608
|
+
},
|
|
598
609
|
},
|
|
599
610
|
outDir: 'dist',
|
|
600
611
|
minify: 'terser',
|
|
601
|
-
sourcemap: true
|
|
612
|
+
sourcemap: true,
|
|
602
613
|
},
|
|
603
614
|
resolve: {
|
|
604
615
|
alias: {
|
|
605
|
-
'@': resolve(__dirname, 'src')
|
|
606
|
-
}
|
|
607
|
-
}
|
|
616
|
+
'@': resolve(__dirname, 'src'),
|
|
617
|
+
},
|
|
618
|
+
},
|
|
608
619
|
});
|
|
609
620
|
```
|
|
610
621
|
|
|
@@ -666,6 +677,7 @@ zip -r my-portfolio-addon.zip \
|
|
|
666
677
|
### Package Structure
|
|
667
678
|
|
|
668
679
|
Your final package should contain:
|
|
680
|
+
|
|
669
681
|
- `manifest.json` - Addon metadata
|
|
670
682
|
- `dist/addon.js` - Compiled addon code
|
|
671
683
|
- `assets/` - Static assets (optional)
|
|
@@ -702,6 +714,7 @@ npm run dev
|
|
|
702
714
|
Add an item to the application sidebar.
|
|
703
715
|
|
|
704
716
|
**Parameters:**
|
|
717
|
+
|
|
705
718
|
- `config.id` (string): Unique identifier
|
|
706
719
|
- `config.label` (string): Display text
|
|
707
720
|
- `config.icon` (string | ReactNode): Icon name or component
|
|
@@ -716,6 +729,7 @@ Add an item to the application sidebar.
|
|
|
716
729
|
Register a new route in the application.
|
|
717
730
|
|
|
718
731
|
**Parameters:**
|
|
732
|
+
|
|
719
733
|
- `route.path` (string): Route path pattern
|
|
720
734
|
- `route.component` (LazyExoticComponent): Lazy-loaded component
|
|
721
735
|
|
|
@@ -724,6 +738,7 @@ Register a new route in the application.
|
|
|
724
738
|
Register cleanup callback for addon disable.
|
|
725
739
|
|
|
726
740
|
**Parameters:**
|
|
741
|
+
|
|
727
742
|
- `callback` (function): Cleanup function
|
|
728
743
|
|
|
729
744
|
### Data Access APIs
|
|
@@ -737,7 +752,7 @@ const ctx = getAddonContext();
|
|
|
737
752
|
const holdings = await ctx.api.portfolio.getHoldings(accountId);
|
|
738
753
|
const accounts = await ctx.api.accounts.getAll();
|
|
739
754
|
|
|
740
|
-
// Market data
|
|
755
|
+
// Market data
|
|
741
756
|
const quotes = await ctx.api.marketData.getQuoteHistory(symbol);
|
|
742
757
|
const profile = await ctx.api.marketData.getAssetProfile(assetId);
|
|
743
758
|
|
|
@@ -756,22 +771,22 @@ ctx.api.logger.debug('Debug info:', debugData);
|
|
|
756
771
|
|
|
757
772
|
### Available API Methods
|
|
758
773
|
|
|
759
|
-
| Method
|
|
760
|
-
|
|
761
|
-
| `portfolio.getHoldings(accountId)`
|
|
762
|
-
| `portfolio.getHolding(accountId, assetId)`
|
|
763
|
-
| `portfolio.calculatePerformanceSummary(params)` | Calculate performance metrics
|
|
764
|
-
| `portfolio.getIncomeSummary()`
|
|
765
|
-
| `accounts.getAll()`
|
|
766
|
-
| `accounts.create(account)`
|
|
767
|
-
| `activities.getAll(params)`
|
|
768
|
-
| `activities.create(activity)`
|
|
769
|
-
| `marketData.getQuoteHistory(symbol)`
|
|
770
|
-
| `marketData.getAssetProfile(assetId)`
|
|
771
|
-
| `marketData.searchTicker(query)`
|
|
772
|
-
| `goals.getAll()`
|
|
773
|
-
| `settings.get()`
|
|
774
|
-
| `query.getClient()`
|
|
774
|
+
| Method | Description | Permission Required |
|
|
775
|
+
| ----------------------------------------------- | ---------------------------------- | -------------------- |
|
|
776
|
+
| `portfolio.getHoldings(accountId)` | Get portfolio holdings for account | `portfolio` |
|
|
777
|
+
| `portfolio.getHolding(accountId, assetId)` | Get specific holding | `portfolio` |
|
|
778
|
+
| `portfolio.calculatePerformanceSummary(params)` | Calculate performance metrics | `portfolio` |
|
|
779
|
+
| `portfolio.getIncomeSummary()` | Get income summary data | `portfolio` |
|
|
780
|
+
| `accounts.getAll()` | Get all account information | `accounts` |
|
|
781
|
+
| `accounts.create(account)` | Create new account | `accounts` |
|
|
782
|
+
| `activities.getAll(params)` | Get activity history | `activities` |
|
|
783
|
+
| `activities.create(activity)` | Create new activity | `activities` |
|
|
784
|
+
| `marketData.getQuoteHistory(symbol)` | Get historical quotes | `market-data` |
|
|
785
|
+
| `marketData.getAssetProfile(assetId)` | Get asset profile | `market-data` |
|
|
786
|
+
| `marketData.searchTicker(query)` | Search for tickers | `market-data` |
|
|
787
|
+
| `goals.getAll()` | Get financial goals | `financial-planning` |
|
|
788
|
+
| `settings.get()` | Get app settings | `settings` |
|
|
789
|
+
| `query.getClient()` | Get shared QueryClient instance | None |
|
|
775
790
|
|
|
776
791
|
### Logger API
|
|
777
792
|
|
|
@@ -797,7 +812,8 @@ if (ctx.api.logger.isLevelEnabled('debug')) {
|
|
|
797
812
|
|
|
798
813
|
### Shared QueryClient Integration
|
|
799
814
|
|
|
800
|
-
The SDK provides access to Wealthfolio's shared React Query client for
|
|
815
|
+
The SDK provides access to Wealthfolio's shared React Query client for
|
|
816
|
+
consistent data fetching and caching:
|
|
801
817
|
|
|
802
818
|
```typescript
|
|
803
819
|
// Access the shared QueryClient instance
|
|
@@ -830,6 +846,7 @@ function MyAddonComponent() {
|
|
|
830
846
|
```
|
|
831
847
|
|
|
832
848
|
**Benefits of Shared QueryClient:**
|
|
849
|
+
|
|
833
850
|
- **Consistent Caching**: Share cache with the main application
|
|
834
851
|
- **Performance**: Avoid duplicate API calls across addons
|
|
835
852
|
- **Synchronization**: Real-time updates when data changes
|
|
@@ -840,6 +857,7 @@ function MyAddonComponent() {
|
|
|
840
857
|
### From v1.0.0 to v1.1.0
|
|
841
858
|
|
|
842
859
|
#### Context Access
|
|
860
|
+
|
|
843
861
|
```typescript
|
|
844
862
|
// Before
|
|
845
863
|
import ctx from '@wealthfolio/addon-sdk';
|
|
@@ -850,6 +868,7 @@ const ctx = getAddonContext();
|
|
|
850
868
|
```
|
|
851
869
|
|
|
852
870
|
#### Type Imports
|
|
871
|
+
|
|
853
872
|
```typescript
|
|
854
873
|
// Before
|
|
855
874
|
import type { AddonContext, AddonManifest } from '@wealthfolio/addon-sdk';
|
|
@@ -887,6 +906,7 @@ npm install --save-dev @types/react-dom
|
|
|
887
906
|
Create the essential configuration files:
|
|
888
907
|
|
|
889
908
|
**tsconfig.json**
|
|
909
|
+
|
|
890
910
|
```json
|
|
891
911
|
{
|
|
892
912
|
"compilerOptions": {
|
|
@@ -916,6 +936,7 @@ Create the essential configuration files:
|
|
|
916
936
|
```
|
|
917
937
|
|
|
918
938
|
**vite.config.ts**
|
|
939
|
+
|
|
919
940
|
```typescript
|
|
920
941
|
import { defineConfig } from 'vite';
|
|
921
942
|
import react from '@vitejs/plugin-react';
|
|
@@ -928,30 +949,31 @@ export default defineConfig({
|
|
|
928
949
|
entry: resolve(__dirname, 'src/index.ts'),
|
|
929
950
|
name: 'MyPortfolioAddon',
|
|
930
951
|
fileName: 'addon',
|
|
931
|
-
formats: ['es']
|
|
952
|
+
formats: ['es'],
|
|
932
953
|
},
|
|
933
954
|
rollupOptions: {
|
|
934
955
|
external: ['react', 'react-dom'],
|
|
935
956
|
output: {
|
|
936
957
|
globals: {
|
|
937
958
|
react: 'React',
|
|
938
|
-
'react-dom': 'ReactDOM'
|
|
939
|
-
}
|
|
940
|
-
}
|
|
959
|
+
'react-dom': 'ReactDOM',
|
|
960
|
+
},
|
|
961
|
+
},
|
|
941
962
|
},
|
|
942
963
|
outDir: 'dist',
|
|
943
964
|
minify: 'terser',
|
|
944
|
-
sourcemap: true
|
|
965
|
+
sourcemap: true,
|
|
945
966
|
},
|
|
946
967
|
resolve: {
|
|
947
968
|
alias: {
|
|
948
|
-
'@': resolve(__dirname, 'src')
|
|
949
|
-
}
|
|
950
|
-
}
|
|
969
|
+
'@': resolve(__dirname, 'src'),
|
|
970
|
+
},
|
|
971
|
+
},
|
|
951
972
|
});
|
|
952
973
|
```
|
|
953
974
|
|
|
954
975
|
**package.json scripts**
|
|
976
|
+
|
|
955
977
|
```json
|
|
956
978
|
{
|
|
957
979
|
"scripts": {
|
|
@@ -1013,10 +1035,10 @@ export default defineConfig({
|
|
|
1013
1035
|
permissions: 'src/permissions.ts',
|
|
1014
1036
|
},
|
|
1015
1037
|
format: ['esm'],
|
|
1016
|
-
dts: true,
|
|
1017
|
-
clean: true,
|
|
1018
|
-
sourcemap: true,
|
|
1019
|
-
minify: false,
|
|
1038
|
+
dts: true, // Generate TypeScript declarations
|
|
1039
|
+
clean: true, // Clean dist folder before build
|
|
1040
|
+
sourcemap: true, // Generate source maps
|
|
1041
|
+
minify: false, // Keep code readable for debugging
|
|
1020
1042
|
target: 'es2020',
|
|
1021
1043
|
external: ['react'], // Don't bundle React
|
|
1022
1044
|
});
|
|
@@ -1071,6 +1093,7 @@ ctx.api.logger.debug('Debug information:', data);
|
|
|
1071
1093
|
#### 2. Development Console
|
|
1072
1094
|
|
|
1073
1095
|
Access the browser's developer console for debugging:
|
|
1096
|
+
|
|
1074
1097
|
- Open Wealthfolio
|
|
1075
1098
|
- Press F12 or right-click → Inspect
|
|
1076
1099
|
- Check Console tab for addon logs
|
|
@@ -1099,24 +1122,24 @@ import { getAddonContext } from '@wealthfolio/addon-sdk';
|
|
|
1099
1122
|
|
|
1100
1123
|
async function fetchPortfolioData() {
|
|
1101
1124
|
const ctx = getAddonContext();
|
|
1102
|
-
|
|
1125
|
+
|
|
1103
1126
|
try {
|
|
1104
1127
|
// Get all accounts first, then holdings for each
|
|
1105
1128
|
const accounts = await ctx.api.accounts.getAll();
|
|
1106
1129
|
const holdings = await Promise.all(
|
|
1107
|
-
accounts.map(account => ctx.api.portfolio.getHoldings(account.id))
|
|
1108
|
-
).then(results => results.flat());
|
|
1130
|
+
accounts.map((account) => ctx.api.portfolio.getHoldings(account.id)),
|
|
1131
|
+
).then((results) => results.flat());
|
|
1109
1132
|
return holdings;
|
|
1110
1133
|
} catch (error) {
|
|
1111
1134
|
ctx.api.logger.error('Failed to fetch holdings:', error);
|
|
1112
|
-
|
|
1135
|
+
|
|
1113
1136
|
// Handle different error types
|
|
1114
1137
|
if (error.code === 'PERMISSION_DENIED') {
|
|
1115
1138
|
// Show permission error to user
|
|
1116
1139
|
} else if (error.code === 'NETWORK_ERROR') {
|
|
1117
1140
|
// Handle network issues
|
|
1118
1141
|
}
|
|
1119
|
-
|
|
1142
|
+
|
|
1120
1143
|
throw error;
|
|
1121
1144
|
}
|
|
1122
1145
|
}
|
|
@@ -1127,14 +1150,14 @@ async function fetchPortfolioData() {
|
|
|
1127
1150
|
```typescript
|
|
1128
1151
|
export default function enable(context: AddonContext) {
|
|
1129
1152
|
const subscriptions: (() => void)[] = [];
|
|
1130
|
-
|
|
1153
|
+
|
|
1131
1154
|
// Add event listeners
|
|
1132
1155
|
const unsubscribe = context.events.subscribe('portfolio.updated', handler);
|
|
1133
1156
|
subscriptions.push(unsubscribe);
|
|
1134
|
-
|
|
1157
|
+
|
|
1135
1158
|
// Cleanup on disable
|
|
1136
1159
|
context.onDisable(() => {
|
|
1137
|
-
subscriptions.forEach(unsub => unsub());
|
|
1160
|
+
subscriptions.forEach((unsub) => unsub());
|
|
1138
1161
|
context.api.logger.info('Addon cleaned up successfully');
|
|
1139
1162
|
});
|
|
1140
1163
|
}
|
|
@@ -1152,7 +1175,7 @@ const AddonStateContext = createContext<AddonState | null>(null);
|
|
|
1152
1175
|
|
|
1153
1176
|
export function AddonProvider({ children }: { children: ReactNode }) {
|
|
1154
1177
|
const [state, setState] = useState<AddonState>(initialState);
|
|
1155
|
-
|
|
1178
|
+
|
|
1156
1179
|
return (
|
|
1157
1180
|
<AddonStateContext.Provider value={{ state, setState }}>
|
|
1158
1181
|
{children}
|
|
@@ -1188,7 +1211,7 @@ function usePortfolioData(accountId: string) {
|
|
|
1188
1211
|
{
|
|
1189
1212
|
staleTime: 5 * 60 * 1000, // 5 minutes
|
|
1190
1213
|
cacheTime: 10 * 60 * 1000, // 10 minutes
|
|
1191
|
-
}
|
|
1214
|
+
},
|
|
1192
1215
|
);
|
|
1193
1216
|
}
|
|
1194
1217
|
```
|
|
@@ -1204,10 +1227,10 @@ export default defineConfig({
|
|
|
1204
1227
|
manualChunks: {
|
|
1205
1228
|
vendor: ['react', 'react-dom'],
|
|
1206
1229
|
charts: ['chart.js', 'd3'],
|
|
1207
|
-
}
|
|
1208
|
-
}
|
|
1209
|
-
}
|
|
1210
|
-
}
|
|
1230
|
+
},
|
|
1231
|
+
},
|
|
1232
|
+
},
|
|
1233
|
+
},
|
|
1211
1234
|
});
|
|
1212
1235
|
```
|
|
1213
1236
|
|
|
@@ -1218,33 +1241,37 @@ We welcome contributions to improve the addon SDK!
|
|
|
1218
1241
|
### Development Setup
|
|
1219
1242
|
|
|
1220
1243
|
1. **Fork and Clone**
|
|
1244
|
+
|
|
1221
1245
|
```bash
|
|
1222
1246
|
git clone https://github.com/yourusername/wealthfolio.git
|
|
1223
1247
|
cd wealthfolio/packages/addon-sdk
|
|
1224
1248
|
```
|
|
1225
1249
|
|
|
1226
1250
|
2. **Install Dependencies**
|
|
1251
|
+
|
|
1227
1252
|
```bash
|
|
1228
1253
|
pnpm install
|
|
1229
1254
|
```
|
|
1230
1255
|
|
|
1231
1256
|
3. **Make Changes**
|
|
1257
|
+
|
|
1232
1258
|
```bash
|
|
1233
1259
|
# Start development mode
|
|
1234
1260
|
pnpm dev
|
|
1235
|
-
|
|
1261
|
+
|
|
1236
1262
|
# Run type checking
|
|
1237
1263
|
pnpm lint
|
|
1238
|
-
|
|
1264
|
+
|
|
1239
1265
|
# Build for testing
|
|
1240
1266
|
pnpm build
|
|
1241
1267
|
```
|
|
1242
1268
|
|
|
1243
1269
|
4. **Testing Your Changes**
|
|
1270
|
+
|
|
1244
1271
|
```bash
|
|
1245
1272
|
# Link the SDK locally for testing
|
|
1246
1273
|
npm link
|
|
1247
|
-
|
|
1274
|
+
|
|
1248
1275
|
# In your test addon project
|
|
1249
1276
|
npm link @wealthfolio/addon-sdk
|
|
1250
1277
|
```
|
|
@@ -1267,13 +1294,13 @@ We welcome contributions to improve the addon SDK!
|
|
|
1267
1294
|
|
|
1268
1295
|
### Package Details
|
|
1269
1296
|
|
|
1270
|
-
| Field
|
|
1271
|
-
|
|
1272
|
-
| **Package Name** | `@wealthfolio/addon-sdk`
|
|
1273
|
-
| **Scope**
|
|
1274
|
-
| **Registry**
|
|
1275
|
-
| **License**
|
|
1276
|
-
| **Repository**
|
|
1297
|
+
| Field | Value |
|
|
1298
|
+
| ---------------- | ----------------------------------------------------------------- |
|
|
1299
|
+
| **Package Name** | `@wealthfolio/addon-sdk` |
|
|
1300
|
+
| **Scope** | `@wealthfolio` |
|
|
1301
|
+
| **Registry** | [npmjs.com](https://www.npmjs.com/package/@wealthfolio/addon-sdk) |
|
|
1302
|
+
| **License** | MIT |
|
|
1303
|
+
| **Repository** | [GitHub](https://github.com/afadil/wealthfolio) |
|
|
1277
1304
|
|
|
1278
1305
|
### Version History
|
|
1279
1306
|
|
|
@@ -1285,14 +1312,15 @@ We follow [Semantic Versioning](https://semver.org/) (SemVer):
|
|
|
1285
1312
|
|
|
1286
1313
|
#### Version Compatibility
|
|
1287
1314
|
|
|
1288
|
-
| SDK Version | Wealthfolio Version | Node.js
|
|
1289
|
-
|
|
1290
|
-
| 1.0.x
|
|
1291
|
-
| 0.9.x
|
|
1315
|
+
| SDK Version | Wealthfolio Version | Node.js | React |
|
|
1316
|
+
| ----------- | ------------------- | --------- | ------- |
|
|
1317
|
+
| 1.0.x | >= 1.0.0 | >= 18.0.0 | ^18.0.0 |
|
|
1318
|
+
| 0.9.x | >= 0.9.0 | >= 16.0.0 | ^17.0.0 |
|
|
1292
1319
|
|
|
1293
1320
|
### Installation from Registry
|
|
1294
1321
|
|
|
1295
1322
|
#### Stable Release
|
|
1323
|
+
|
|
1296
1324
|
```bash
|
|
1297
1325
|
# Latest stable version
|
|
1298
1326
|
npm install @wealthfolio/addon-sdk
|
|
@@ -1305,6 +1333,7 @@ npm install @wealthfolio/addon-sdk@^1.0.0
|
|
|
1305
1333
|
```
|
|
1306
1334
|
|
|
1307
1335
|
#### Beta/Preview Releases
|
|
1336
|
+
|
|
1308
1337
|
```bash
|
|
1309
1338
|
# Latest beta version
|
|
1310
1339
|
npm install @wealthfolio/addon-sdk@beta
|
|
@@ -1314,6 +1343,7 @@ npm install @wealthfolio/addon-sdk@1.1.0-beta.1
|
|
|
1314
1343
|
```
|
|
1315
1344
|
|
|
1316
1345
|
#### Development Version
|
|
1346
|
+
|
|
1317
1347
|
```bash
|
|
1318
1348
|
# Install directly from GitHub
|
|
1319
1349
|
npm install github:afadil/wealthfolio#main
|
|
@@ -1344,6 +1374,7 @@ npm outdated @wealthfolio/addon-sdk
|
|
|
1344
1374
|
### Publishing Information (For Maintainers)
|
|
1345
1375
|
|
|
1346
1376
|
#### Prerequisites
|
|
1377
|
+
|
|
1347
1378
|
```bash
|
|
1348
1379
|
# Login to npm (maintainers only)
|
|
1349
1380
|
npm login
|
|
@@ -1356,6 +1387,7 @@ npm access list packages @wealthfolio
|
|
|
1356
1387
|
```
|
|
1357
1388
|
|
|
1358
1389
|
#### Release Process
|
|
1390
|
+
|
|
1359
1391
|
```bash
|
|
1360
1392
|
# 1. Update version
|
|
1361
1393
|
npm version patch # or minor/major
|
|
@@ -1380,23 +1412,28 @@ git push --tags
|
|
|
1380
1412
|
|
|
1381
1413
|
#### Distribution Tags
|
|
1382
1414
|
|
|
1383
|
-
| Tag
|
|
1384
|
-
|
|
1385
|
-
| `latest` | Stable releases
|
|
1386
|
-
| `beta`
|
|
1387
|
-
| `alpha`
|
|
1388
|
-
| `next`
|
|
1415
|
+
| Tag | Purpose | Command |
|
|
1416
|
+
| -------- | ------------------ | ------------------------- |
|
|
1417
|
+
| `latest` | Stable releases | `npm publish` |
|
|
1418
|
+
| `beta` | Beta releases | `npm publish --tag beta` |
|
|
1419
|
+
| `alpha` | Alpha releases | `npm publish --tag alpha` |
|
|
1420
|
+
| `next` | Next major version | `npm publish --tag next` |
|
|
1389
1421
|
|
|
1390
1422
|
#### Package Metrics
|
|
1391
1423
|
|
|
1392
1424
|
View package statistics:
|
|
1393
|
-
|
|
1394
|
-
- **
|
|
1395
|
-
|
|
1425
|
+
|
|
1426
|
+
- **Downloads**:
|
|
1427
|
+
[npm-stat.com](https://npm-stat.com/charts.html?package=@wealthfolio/addon-sdk)
|
|
1428
|
+
- **Bundle Size**:
|
|
1429
|
+
[bundlephobia.com](https://bundlephobia.com/package/@wealthfolio/addon-sdk)
|
|
1430
|
+
- **Dependencies**:
|
|
1431
|
+
[npm.anvaka.com](https://npm.anvaka.com/#/view/2d/@wealthfolio/addon-sdk)
|
|
1396
1432
|
|
|
1397
1433
|
### Security
|
|
1398
1434
|
|
|
1399
1435
|
#### Vulnerability Scanning
|
|
1436
|
+
|
|
1400
1437
|
```bash
|
|
1401
1438
|
# Check for vulnerabilities
|
|
1402
1439
|
npm audit
|
|
@@ -1409,6 +1446,7 @@ npm audit --audit-level=moderate
|
|
|
1409
1446
|
```
|
|
1410
1447
|
|
|
1411
1448
|
#### Package Integrity
|
|
1449
|
+
|
|
1412
1450
|
```bash
|
|
1413
1451
|
# Verify package integrity
|
|
1414
1452
|
npm pack --dry-run
|
|
@@ -1422,7 +1460,8 @@ npm pack && tar -tf *.tgz
|
|
|
1422
1460
|
#### Package Support Policy
|
|
1423
1461
|
|
|
1424
1462
|
- **Latest Major Version**: Full support with new features and bug fixes
|
|
1425
|
-
- **Previous Major Version**: Security fixes and critical bug fixes for 12
|
|
1463
|
+
- **Previous Major Version**: Security fixes and critical bug fixes for 12
|
|
1464
|
+
months
|
|
1426
1465
|
- **Older Versions**: Community support only
|
|
1427
1466
|
|
|
1428
1467
|
#### Maintenance Schedule
|
|
@@ -1433,9 +1472,11 @@ npm pack && tar -tf *.tgz
|
|
|
1433
1472
|
|
|
1434
1473
|
#### Getting Help
|
|
1435
1474
|
|
|
1436
|
-
1. **Documentation**: Check this README and
|
|
1475
|
+
1. **Documentation**: Check this README and
|
|
1476
|
+
[docs](https://docs.wealthfolio.app/addons)
|
|
1437
1477
|
2. **Issues**: [GitHub Issues](https://github.com/afadil/wealthfolio/issues)
|
|
1438
|
-
3. **Discussions**:
|
|
1478
|
+
3. **Discussions**:
|
|
1479
|
+
[GitHub Discussions](https://github.com/afadil/wealthfolio/discussions)
|
|
1439
1480
|
4. **Discord**: [Community Discord](https://discord.gg/wealthfolio)
|
|
1440
1481
|
5. **Email**: [support@wealthfolio.app](mailto:support@wealthfolio.app)
|
|
1441
1482
|
|
|
@@ -1466,6 +1507,7 @@ MIT - see [LICENSE](LICENSE) for details.
|
|
|
1466
1507
|
**Error**: `Cannot resolve module '@wealthfolio/addon-sdk'`
|
|
1467
1508
|
|
|
1468
1509
|
**Solutions**:
|
|
1510
|
+
|
|
1469
1511
|
```bash
|
|
1470
1512
|
# Clear npm cache
|
|
1471
1513
|
npm cache clean --force
|
|
@@ -1483,6 +1525,7 @@ node --version
|
|
|
1483
1525
|
**Error**: `Cannot find type definitions`
|
|
1484
1526
|
|
|
1485
1527
|
**Solutions**:
|
|
1528
|
+
|
|
1486
1529
|
```typescript
|
|
1487
1530
|
// Ensure proper TypeScript configuration
|
|
1488
1531
|
{
|
|
@@ -1502,6 +1545,7 @@ import type { AddonContext } from '@wealthfolio/addon-sdk';
|
|
|
1502
1545
|
**Error**: `React version mismatch`
|
|
1503
1546
|
|
|
1504
1547
|
**Solutions**:
|
|
1548
|
+
|
|
1505
1549
|
```bash
|
|
1506
1550
|
# Install correct React version
|
|
1507
1551
|
npm install react@^18.0.0 react-dom@^18.0.0
|
|
@@ -1515,14 +1559,15 @@ npm list react react-dom
|
|
|
1515
1559
|
**Error**: `Vite build fails with external dependencies`
|
|
1516
1560
|
|
|
1517
1561
|
**Solutions**:
|
|
1562
|
+
|
|
1518
1563
|
```typescript
|
|
1519
1564
|
// vite.config.ts
|
|
1520
1565
|
export default defineConfig({
|
|
1521
1566
|
build: {
|
|
1522
1567
|
rollupOptions: {
|
|
1523
|
-
external: ['react', 'react-dom', '@wealthfolio/addon-sdk']
|
|
1524
|
-
}
|
|
1525
|
-
}
|
|
1568
|
+
external: ['react', 'react-dom', '@wealthfolio/addon-sdk'],
|
|
1569
|
+
},
|
|
1570
|
+
},
|
|
1526
1571
|
});
|
|
1527
1572
|
```
|
|
1528
1573
|
|
|
@@ -1531,6 +1576,7 @@ export default defineConfig({
|
|
|
1531
1576
|
**Error**: `Permission denied for API call`
|
|
1532
1577
|
|
|
1533
1578
|
**Solutions**:
|
|
1579
|
+
|
|
1534
1580
|
```json
|
|
1535
1581
|
// Add required permissions to manifest.json
|
|
1536
1582
|
{
|
|
@@ -1549,6 +1595,7 @@ export default defineConfig({
|
|
|
1549
1595
|
**Error**: `getAddonContext() returns undefined`
|
|
1550
1596
|
|
|
1551
1597
|
**Solutions**:
|
|
1598
|
+
|
|
1552
1599
|
```typescript
|
|
1553
1600
|
// Ensure you're calling it within addon context
|
|
1554
1601
|
function MyComponent() {
|
|
@@ -1578,6 +1625,7 @@ ls -la dist/ # Should update when you save files
|
|
|
1578
1625
|
#### 2. Addon Not Loading in Wealthfolio
|
|
1579
1626
|
|
|
1580
1627
|
1. Check the addon package structure:
|
|
1628
|
+
|
|
1581
1629
|
```
|
|
1582
1630
|
addon.zip
|
|
1583
1631
|
├── manifest.json ✓
|
|
@@ -1587,6 +1635,7 @@ ls -la dist/ # Should update when you save files
|
|
|
1587
1635
|
```
|
|
1588
1636
|
|
|
1589
1637
|
2. Validate manifest.json:
|
|
1638
|
+
|
|
1590
1639
|
```bash
|
|
1591
1640
|
# Check JSON syntax
|
|
1592
1641
|
cat manifest.json | jq .
|
|
@@ -1606,10 +1655,10 @@ try {
|
|
|
1606
1655
|
const data = await ctx.api.portfolio.getHoldings(accounts[0]?.id);
|
|
1607
1656
|
ctx.api.logger.info('Data loaded successfully', { count: data.length });
|
|
1608
1657
|
} catch (error) {
|
|
1609
|
-
ctx.api.logger.error('API call failed', {
|
|
1658
|
+
ctx.api.logger.error('API call failed', {
|
|
1610
1659
|
error: error.message,
|
|
1611
1660
|
stack: error.stack,
|
|
1612
|
-
timestamp: new Date().toISOString()
|
|
1661
|
+
timestamp: new Date().toISOString(),
|
|
1613
1662
|
});
|
|
1614
1663
|
}
|
|
1615
1664
|
```
|
|
@@ -1630,11 +1679,11 @@ export default defineConfig({
|
|
|
1630
1679
|
output: {
|
|
1631
1680
|
manualChunks: {
|
|
1632
1681
|
vendor: ['react', 'react-dom'],
|
|
1633
|
-
utils: ['lodash', 'date-fns']
|
|
1634
|
-
}
|
|
1635
|
-
}
|
|
1636
|
-
}
|
|
1637
|
-
}
|
|
1682
|
+
utils: ['lodash', 'date-fns'],
|
|
1683
|
+
},
|
|
1684
|
+
},
|
|
1685
|
+
},
|
|
1686
|
+
},
|
|
1638
1687
|
});
|
|
1639
1688
|
```
|
|
1640
1689
|
|
|
@@ -1644,7 +1693,7 @@ export default defineConfig({
|
|
|
1644
1693
|
// Proper cleanup in useEffect
|
|
1645
1694
|
useEffect(() => {
|
|
1646
1695
|
const subscription = ctx.events.subscribe('update', handler);
|
|
1647
|
-
|
|
1696
|
+
|
|
1648
1697
|
return () => {
|
|
1649
1698
|
subscription.unsubscribe(); // ✓ Clean up
|
|
1650
1699
|
};
|
|
@@ -1663,6 +1712,7 @@ context.onDisable(() => {
|
|
|
1663
1712
|
If you're still experiencing issues:
|
|
1664
1713
|
|
|
1665
1714
|
1. **Check Version Compatibility**:
|
|
1715
|
+
|
|
1666
1716
|
```bash
|
|
1667
1717
|
npm list @wealthfolio/addon-sdk
|
|
1668
1718
|
```
|
|
@@ -1680,4 +1730,4 @@ If you're still experiencing issues:
|
|
|
1680
1730
|
- Node.js version
|
|
1681
1731
|
- Operating system
|
|
1682
1732
|
- Error messages with stack traces
|
|
1683
|
-
- Minimal reproduction steps
|
|
1733
|
+
- Minimal reproduction steps
|