@firela/billclaw-core 0.1.3
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/LICENSE +21 -0
- package/README.md +109 -0
- package/dist/billclaw.d.ts +76 -0
- package/dist/billclaw.d.ts.map +1 -0
- package/dist/billclaw.js +205 -0
- package/dist/billclaw.js.map +1 -0
- package/dist/credentials/index.d.ts +8 -0
- package/dist/credentials/index.d.ts.map +1 -0
- package/dist/credentials/index.js +8 -0
- package/dist/credentials/index.js.map +1 -0
- package/dist/credentials/keychain.d.ts +92 -0
- package/dist/credentials/keychain.d.ts.map +1 -0
- package/dist/credentials/keychain.js +172 -0
- package/dist/credentials/keychain.js.map +1 -0
- package/dist/credentials/store.d.ts +76 -0
- package/dist/credentials/store.d.ts.map +1 -0
- package/dist/credentials/store.js +144 -0
- package/dist/credentials/store.js.map +1 -0
- package/dist/errors/errors.d.ts +92 -0
- package/dist/errors/errors.d.ts.map +1 -0
- package/dist/errors/errors.js +315 -0
- package/dist/errors/errors.js.map +1 -0
- package/dist/errors/index.d.ts +7 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +7 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/exporters/beancount.d.ts +42 -0
- package/dist/exporters/beancount.d.ts.map +1 -0
- package/dist/exporters/beancount.js +141 -0
- package/dist/exporters/beancount.js.map +1 -0
- package/dist/exporters/index.d.ts +8 -0
- package/dist/exporters/index.d.ts.map +1 -0
- package/dist/exporters/index.js +8 -0
- package/dist/exporters/index.js.map +1 -0
- package/dist/exporters/ledger.d.ts +42 -0
- package/dist/exporters/ledger.d.ts.map +1 -0
- package/dist/exporters/ledger.js +139 -0
- package/dist/exporters/ledger.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -0
- package/dist/models/config.d.ts +552 -0
- package/dist/models/config.d.ts.map +1 -0
- package/dist/models/config.js +168 -0
- package/dist/models/config.js.map +1 -0
- package/dist/models/index.d.ts +7 -0
- package/dist/models/index.d.ts.map +1 -0
- package/dist/models/index.js +8 -0
- package/dist/models/index.js.map +1 -0
- package/dist/runtime/index.d.ts +7 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +7 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/types.d.ts +110 -0
- package/dist/runtime/types.d.ts.map +1 -0
- package/dist/runtime/types.js +85 -0
- package/dist/runtime/types.js.map +1 -0
- package/dist/security/audit.d.ts +148 -0
- package/dist/security/audit.d.ts.map +1 -0
- package/dist/security/audit.js +286 -0
- package/dist/security/audit.js.map +1 -0
- package/dist/security/index.d.ts +7 -0
- package/dist/security/index.d.ts.map +1 -0
- package/dist/security/index.js +7 -0
- package/dist/security/index.js.map +1 -0
- package/dist/services/event-emitter.d.ts +171 -0
- package/dist/services/event-emitter.d.ts.map +1 -0
- package/dist/services/event-emitter.js +287 -0
- package/dist/services/event-emitter.js.map +1 -0
- package/dist/services/index.d.ts +8 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +8 -0
- package/dist/services/index.js.map +1 -0
- package/dist/sources/gmail/bill-recognizer.d.ts +71 -0
- package/dist/sources/gmail/bill-recognizer.d.ts.map +1 -0
- package/dist/sources/gmail/bill-recognizer.js +341 -0
- package/dist/sources/gmail/bill-recognizer.js.map +1 -0
- package/dist/sources/gmail/email-parser.d.ts +68 -0
- package/dist/sources/gmail/email-parser.d.ts.map +1 -0
- package/dist/sources/gmail/email-parser.js +238 -0
- package/dist/sources/gmail/email-parser.js.map +1 -0
- package/dist/sources/gmail/gmail-fetch.d.ts +54 -0
- package/dist/sources/gmail/gmail-fetch.d.ts.map +1 -0
- package/dist/sources/gmail/gmail-fetch.js +300 -0
- package/dist/sources/gmail/gmail-fetch.js.map +1 -0
- package/dist/sources/gmail/index.d.ts +7 -0
- package/dist/sources/gmail/index.d.ts.map +1 -0
- package/dist/sources/gmail/index.js +7 -0
- package/dist/sources/gmail/index.js.map +1 -0
- package/dist/sources/index.d.ts +8 -0
- package/dist/sources/index.d.ts.map +1 -0
- package/dist/sources/index.js +8 -0
- package/dist/sources/index.js.map +1 -0
- package/dist/sources/plaid/index.d.ts +7 -0
- package/dist/sources/plaid/index.d.ts.map +1 -0
- package/dist/sources/plaid/index.js +7 -0
- package/dist/sources/plaid/index.js.map +1 -0
- package/dist/sources/plaid/plaid-sync.d.ts +42 -0
- package/dist/sources/plaid/plaid-sync.d.ts.map +1 -0
- package/dist/sources/plaid/plaid-sync.js +182 -0
- package/dist/sources/plaid/plaid-sync.js.map +1 -0
- package/dist/storage/cache.d.ts +134 -0
- package/dist/storage/cache.d.ts.map +1 -0
- package/dist/storage/cache.js +239 -0
- package/dist/storage/cache.js.map +1 -0
- package/dist/storage/index.d.ts +11 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +11 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/indexes.d.ts +136 -0
- package/dist/storage/indexes.d.ts.map +1 -0
- package/dist/storage/indexes.js +294 -0
- package/dist/storage/indexes.js.map +1 -0
- package/dist/storage/locking.d.ts +103 -0
- package/dist/storage/locking.d.ts.map +1 -0
- package/dist/storage/locking.js +158 -0
- package/dist/storage/locking.js.map +1 -0
- package/dist/storage/streaming.d.ts +102 -0
- package/dist/storage/streaming.d.ts.map +1 -0
- package/dist/storage/streaming.js +245 -0
- package/dist/storage/streaming.js.map +1 -0
- package/dist/storage/transaction-storage.d.ts +101 -0
- package/dist/storage/transaction-storage.d.ts.map +1 -0
- package/dist/storage/transaction-storage.js +193 -0
- package/dist/storage/transaction-storage.js.map +1 -0
- package/dist/sync/index.d.ts +7 -0
- package/dist/sync/index.d.ts.map +1 -0
- package/dist/sync/index.js +7 -0
- package/dist/sync/index.js.map +1 -0
- package/dist/sync/sync-service.d.ts +42 -0
- package/dist/sync/sync-service.d.ts.map +1 -0
- package/dist/sync/sync-service.js +112 -0
- package/dist/sync/sync-service.js.map +1 -0
- package/dist/test-fixtures.d.ts +38 -0
- package/dist/test-fixtures.d.ts.map +1 -0
- package/dist/test-fixtures.js +137 -0
- package/dist/test-fixtures.js.map +1 -0
- package/package.json +68 -0
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error handling utilities for BillClaw
|
|
3
|
+
*
|
|
4
|
+
* Provides user-friendly error messages, recovery suggestions,
|
|
5
|
+
* and troubleshooting guides.
|
|
6
|
+
*
|
|
7
|
+
* Framework-agnostic: Logger is provided via runtime abstraction.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Error categories for better user messaging
|
|
11
|
+
*/
|
|
12
|
+
export var ErrorCategory;
|
|
13
|
+
(function (ErrorCategory) {
|
|
14
|
+
// Configuration errors
|
|
15
|
+
ErrorCategory["CONFIG"] = "configuration";
|
|
16
|
+
ErrorCategory["CREDENTIALS"] = "credentials";
|
|
17
|
+
ErrorCategory["NETWORK"] = "network";
|
|
18
|
+
// Plaid errors
|
|
19
|
+
ErrorCategory["PLAID_API"] = "plaid_api";
|
|
20
|
+
ErrorCategory["PLAID_AUTH"] = "plaid_auth";
|
|
21
|
+
ErrorCategory["PLAID_ITEM"] = "plaid_item";
|
|
22
|
+
// Gmail errors
|
|
23
|
+
ErrorCategory["GMAIL_API"] = "gmail_api";
|
|
24
|
+
ErrorCategory["GMAIL_AUTH"] = "gmail_auth";
|
|
25
|
+
// Storage errors
|
|
26
|
+
ErrorCategory["STORAGE"] = "storage";
|
|
27
|
+
ErrorCategory["FILE_SYSTEM"] = "file_system";
|
|
28
|
+
// General errors
|
|
29
|
+
ErrorCategory["UNKNOWN"] = "unknown";
|
|
30
|
+
})(ErrorCategory || (ErrorCategory = {}));
|
|
31
|
+
/**
|
|
32
|
+
* Create a user-friendly error
|
|
33
|
+
*/
|
|
34
|
+
export function createUserError(category, title, message, suggestions, docsLink, originalError) {
|
|
35
|
+
return {
|
|
36
|
+
type: "UserError",
|
|
37
|
+
category,
|
|
38
|
+
title,
|
|
39
|
+
message,
|
|
40
|
+
suggestions,
|
|
41
|
+
docsLink,
|
|
42
|
+
error: originalError,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Format error for display to user
|
|
47
|
+
*/
|
|
48
|
+
export function formatError(error) {
|
|
49
|
+
const lines = [];
|
|
50
|
+
// Header with category emoji
|
|
51
|
+
const categoryEmoji = getCategoryEmoji(error.category);
|
|
52
|
+
lines.push(`${categoryEmoji} ${error.title}`);
|
|
53
|
+
lines.push("");
|
|
54
|
+
// Message
|
|
55
|
+
lines.push(error.message);
|
|
56
|
+
lines.push("");
|
|
57
|
+
// Suggestions
|
|
58
|
+
if (error.suggestions.length > 0) {
|
|
59
|
+
lines.push("Suggestions:");
|
|
60
|
+
for (let i = 0; i < error.suggestions.length; i++) {
|
|
61
|
+
lines.push(` ${i + 1}. ${error.suggestions[i]}`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// Docs link
|
|
65
|
+
if (error.docsLink) {
|
|
66
|
+
lines.push("");
|
|
67
|
+
lines.push(`Learn more: ${error.docsLink}`);
|
|
68
|
+
}
|
|
69
|
+
return lines.join("\n");
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Get emoji for error category
|
|
73
|
+
*/
|
|
74
|
+
function getCategoryEmoji(category) {
|
|
75
|
+
const emojis = {
|
|
76
|
+
[ErrorCategory.CONFIG]: "⚙️",
|
|
77
|
+
[ErrorCategory.CREDENTIALS]: "🔑",
|
|
78
|
+
[ErrorCategory.NETWORK]: "🌐",
|
|
79
|
+
[ErrorCategory.PLAID_API]: "🏦",
|
|
80
|
+
[ErrorCategory.PLAID_AUTH]: "🔐",
|
|
81
|
+
[ErrorCategory.PLAID_ITEM]: "📝",
|
|
82
|
+
[ErrorCategory.GMAIL_API]: "📧",
|
|
83
|
+
[ErrorCategory.GMAIL_AUTH]: "🔐",
|
|
84
|
+
[ErrorCategory.STORAGE]: "💾",
|
|
85
|
+
[ErrorCategory.FILE_SYSTEM]: "📁",
|
|
86
|
+
[ErrorCategory.UNKNOWN]: "❓",
|
|
87
|
+
};
|
|
88
|
+
return emojis[category] || "❓";
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Parse Plaid error codes and create user-friendly errors
|
|
92
|
+
*/
|
|
93
|
+
export function parsePlaidError(error) {
|
|
94
|
+
const errorCode = error.error_code || "UNKNOWN";
|
|
95
|
+
const errorMessage = error.error_message || error.display_message || "An error occurred";
|
|
96
|
+
const requestId = error.request_id;
|
|
97
|
+
// Login required
|
|
98
|
+
if (errorCode === "ITEM_LOGIN_REQUIRED" ||
|
|
99
|
+
error.error_type === "ITEM_LOGIN_REQUIRED") {
|
|
100
|
+
return createUserError(ErrorCategory.PLAID_AUTH, "Account Re-Authentication Required", "Your bank account requires re-authentication. This happens when your bank credentials have changed or expired.", [
|
|
101
|
+
"Re-authenticate via your adapter's setup command",
|
|
102
|
+
"This will open a secure browser window where you can log into your bank",
|
|
103
|
+
"After re-authentication, your transactions will sync normally",
|
|
104
|
+
], "https://plaid.com/docs/errors/#item-login-required");
|
|
105
|
+
}
|
|
106
|
+
// Invalid credentials
|
|
107
|
+
if (errorCode === "INVALID_ACCESS_TOKEN" ||
|
|
108
|
+
error.error_type === "INVALID_ACCESS_TOKEN") {
|
|
109
|
+
return createUserError(ErrorCategory.PLAID_AUTH, "Invalid Access Token", "Your access token is invalid. This can happen if the token was revoked or corrupted.", [
|
|
110
|
+
"Run your adapter's setup command to reconnect your account",
|
|
111
|
+
"If this persists, remove and re-add the account",
|
|
112
|
+
], "https://plaid.com/docs/errors/#invalid-access-token");
|
|
113
|
+
}
|
|
114
|
+
// Product not ready
|
|
115
|
+
if (errorCode === "PRODUCT_NOT_READY") {
|
|
116
|
+
return createUserError(ErrorCategory.PLAID_API, "Account Not Ready", "Your account is not fully set up yet. Plaid is still processing your account information.", [
|
|
117
|
+
"Wait a few minutes and try again",
|
|
118
|
+
"If this persists, contact Plaid support",
|
|
119
|
+
], "https://plaid.com/docs/errors/#product-not-ready");
|
|
120
|
+
}
|
|
121
|
+
// Rate limit
|
|
122
|
+
if (errorCode === "RATE_LIMIT_EXCEEDED") {
|
|
123
|
+
return createUserError(ErrorCategory.PLAID_API, "API Rate Limit Exceeded", "Too many requests have been made to the Plaid API. Please wait before trying again.", [
|
|
124
|
+
"Wait a few minutes before syncing again",
|
|
125
|
+
"Consider syncing less frequently (e.g., daily instead of hourly)",
|
|
126
|
+
"If you need higher rate limits, upgrade your Plaid plan",
|
|
127
|
+
], "https://plaid.com/docs/errors/#rate-limit-exceeded");
|
|
128
|
+
}
|
|
129
|
+
// Institution down
|
|
130
|
+
if (errorCode === "INSTITUTION_DOWN") {
|
|
131
|
+
return createUserError(ErrorCategory.PLAID_API, "Bank temporarily unavailable", "Your bank's systems are temporarily down for maintenance.", [
|
|
132
|
+
"Wait a few minutes and try again",
|
|
133
|
+
"Check your bank's website for service status updates",
|
|
134
|
+
"Your transactions will sync automatically once the bank is back online",
|
|
135
|
+
], undefined);
|
|
136
|
+
}
|
|
137
|
+
// Invalid credentials
|
|
138
|
+
if (errorCode === "INVALID_CREDENTIALS") {
|
|
139
|
+
return createUserError(ErrorCategory.PLAID_API, "Invalid API Credentials", "The Plaid API credentials configured are invalid.", [
|
|
140
|
+
"Configure your Plaid client ID and secret",
|
|
141
|
+
"Verify your credentials at https://dashboard.plaid.com",
|
|
142
|
+
], "https://dashboard.plaid.com");
|
|
143
|
+
}
|
|
144
|
+
// Generic Plaid error
|
|
145
|
+
return createUserError(ErrorCategory.PLAID_API, "Plaid API Error", `${errorMessage}${requestId ? ` (Request ID: ${requestId})` : ""}`, [
|
|
146
|
+
"Try again in a few minutes",
|
|
147
|
+
"Check Plaid status at https://status.plaid.com",
|
|
148
|
+
], "https://plaid.com/docs/errors/");
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Parse Gmail API errors and create user-friendly errors
|
|
152
|
+
*/
|
|
153
|
+
export function parseGmailError(error) {
|
|
154
|
+
const statusCode = error.status || error.code || 0;
|
|
155
|
+
// Unauthorized
|
|
156
|
+
if (statusCode === 401) {
|
|
157
|
+
return createUserError(ErrorCategory.GMAIL_AUTH, "Gmail Authentication Failed", "Your Gmail access has expired or been revoked. You need to re-authenticate.", [
|
|
158
|
+
"Re-authenticate with Gmail via your adapter's setup command",
|
|
159
|
+
"Make sure you grant read-only access to your Gmail",
|
|
160
|
+
"Check that Google Cloud OAuth credentials are valid",
|
|
161
|
+
], "https://developers.google.com/gmail/api/auth");
|
|
162
|
+
}
|
|
163
|
+
// Forbidden
|
|
164
|
+
if (statusCode === 403) {
|
|
165
|
+
return createUserError(ErrorCategory.GMAIL_API, "Gmail Access Denied", "Access to Gmail was denied. This usually means the OAuth token lacks the required permissions.", [
|
|
166
|
+
"Make sure the Gmail API is enabled in Google Cloud Console",
|
|
167
|
+
"Verify that the OAuth consent screen includes 'gmail.readonly' scope",
|
|
168
|
+
"Re-authenticate to grant proper permissions",
|
|
169
|
+
], "https://developers.google.com/gmail/api/auth");
|
|
170
|
+
}
|
|
171
|
+
// Not found
|
|
172
|
+
if (statusCode === 404) {
|
|
173
|
+
return createUserError(ErrorCategory.GMAIL_API, "Gmail API Not Found", "The Gmail API endpoint could not be found. This may be a configuration issue.", [
|
|
174
|
+
"Verify the Gmail API is enabled in your Google Cloud project",
|
|
175
|
+
"Check that the API name is correct: 'gmail.api'",
|
|
176
|
+
"Try re-enabling the Gmail API in Google Cloud Console",
|
|
177
|
+
], "https://console.cloud.google.com/apis/library/gmail-api");
|
|
178
|
+
}
|
|
179
|
+
// Rate limit
|
|
180
|
+
if (statusCode === 429) {
|
|
181
|
+
return createUserError(ErrorCategory.GMAIL_API, "Gmail API Rate Limit Exceeded", "Too many requests have been made to the Gmail API. You've hit the daily quota limit.", [
|
|
182
|
+
"Wait until tomorrow when the quota resets",
|
|
183
|
+
"Reduce sync frequency to avoid hitting the limit",
|
|
184
|
+
"Consider using Gmail push notifications instead of polling",
|
|
185
|
+
"Free tier: 250 quota units/day",
|
|
186
|
+
], "https://developers.google.com/gmail/api/v1/quota");
|
|
187
|
+
}
|
|
188
|
+
// Generic Gmail error
|
|
189
|
+
return createUserError(ErrorCategory.GMAIL_API, "Gmail API Error", error.message || "An error occurred while communicating with Gmail", [
|
|
190
|
+
"Check your internet connection",
|
|
191
|
+
"Verify Gmail API is enabled in Google Cloud Console",
|
|
192
|
+
"Try again in a few minutes",
|
|
193
|
+
], "https://developers.google.com/gmail/api");
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Parse network errors
|
|
197
|
+
*/
|
|
198
|
+
export function parseNetworkError(error) {
|
|
199
|
+
const message = error.message.toLowerCase();
|
|
200
|
+
// Connection refused
|
|
201
|
+
if (message.includes("econnrefused") ||
|
|
202
|
+
message.includes("connection refused")) {
|
|
203
|
+
return createUserError(ErrorCategory.NETWORK, "Connection Refused", "Could not connect to the server. The service may be down or your network is blocking the connection.", [
|
|
204
|
+
"Check your internet connection",
|
|
205
|
+
"Verify you're not behind a firewall or proxy",
|
|
206
|
+
"If using a VPN, try disconnecting it",
|
|
207
|
+
"Check if the service is temporarily down",
|
|
208
|
+
], undefined);
|
|
209
|
+
}
|
|
210
|
+
// Timeout
|
|
211
|
+
if (message.includes("timeout") || message.includes("timed out")) {
|
|
212
|
+
return createUserError(ErrorCategory.NETWORK, "Request Timeout", "The request took too long to complete. This could be due to slow network or server issues.", [
|
|
213
|
+
"Check your internet connection speed",
|
|
214
|
+
"Try again in a few minutes",
|
|
215
|
+
"If syncing many transactions, consider reducing the date range",
|
|
216
|
+
], undefined);
|
|
217
|
+
}
|
|
218
|
+
// DNS resolution failed
|
|
219
|
+
if (message.includes("enotfound") || message.includes("getaddrinfo")) {
|
|
220
|
+
return createUserError(ErrorCategory.NETWORK, "DNS Resolution Failed", "Could not resolve the server address. This might be a DNS or network configuration issue.", [
|
|
221
|
+
"Check your internet connection",
|
|
222
|
+
"Try switching to a different DNS server (e.g., 8.8.8.8)",
|
|
223
|
+
"Flush your DNS cache",
|
|
224
|
+
"If you're using a VPN, try disconnecting it",
|
|
225
|
+
], undefined);
|
|
226
|
+
}
|
|
227
|
+
// Generic network error
|
|
228
|
+
return createUserError(ErrorCategory.NETWORK, "Network Error", error.message || "An error occurred while communicating with the server", [
|
|
229
|
+
"Check your internet connection",
|
|
230
|
+
"Try again in a few minutes",
|
|
231
|
+
"If the problem persists, check your network settings",
|
|
232
|
+
], undefined);
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Parse file system errors
|
|
236
|
+
*/
|
|
237
|
+
export function parseFileSystemError(error, filePath) {
|
|
238
|
+
const code = error.code;
|
|
239
|
+
const message = error.message;
|
|
240
|
+
// Permission denied
|
|
241
|
+
if (code === "EACCES" || code === "EPERM") {
|
|
242
|
+
return createUserError(ErrorCategory.FILE_SYSTEM, "Permission Denied", `Cannot access ${filePath || "file or directory"}. You don't have the required permissions.`, [
|
|
243
|
+
"Check file/directory permissions",
|
|
244
|
+
"Ensure the user has read/write access to the data directory",
|
|
245
|
+
], undefined);
|
|
246
|
+
}
|
|
247
|
+
// No space left
|
|
248
|
+
if (code === "ENOSPC") {
|
|
249
|
+
return createUserError(ErrorCategory.STORAGE, "Disk Full", "No space left on device. Cannot save transactions.", [
|
|
250
|
+
"Free up disk space by deleting unnecessary files",
|
|
251
|
+
"Consider moving the BillClaw data directory to a drive with more space",
|
|
252
|
+
], undefined);
|
|
253
|
+
}
|
|
254
|
+
// Directory not found
|
|
255
|
+
if (code === "ENOENT" && message.includes("no such file")) {
|
|
256
|
+
return createUserError(ErrorCategory.FILE_SYSTEM, "File or Directory Not Found", `The file or directory ${filePath || ""} does not exist.`, [
|
|
257
|
+
"Run setup to initialize BillClaw",
|
|
258
|
+
"Verify the data directory path is correct",
|
|
259
|
+
], undefined);
|
|
260
|
+
}
|
|
261
|
+
// Generic file system error
|
|
262
|
+
return createUserError(ErrorCategory.FILE_SYSTEM, "File System Error", message || "An error occurred while accessing the file system", [
|
|
263
|
+
"Check file/directory permissions",
|
|
264
|
+
"Ensure the data directory exists and is writable",
|
|
265
|
+
"Try running setup to reinitialize",
|
|
266
|
+
], undefined);
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Type guard to check if error is a UserError
|
|
270
|
+
*/
|
|
271
|
+
export function isUserError(error) {
|
|
272
|
+
return (typeof error === "object" &&
|
|
273
|
+
error !== null &&
|
|
274
|
+
"type" in error &&
|
|
275
|
+
error.type === "UserError");
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Log error with context for debugging
|
|
279
|
+
*/
|
|
280
|
+
export function logError(logger, error, context) {
|
|
281
|
+
const logData = {
|
|
282
|
+
timestamp: new Date().toISOString(),
|
|
283
|
+
category: isUserError(error) ? error.category : ErrorCategory.UNKNOWN,
|
|
284
|
+
message: error.message,
|
|
285
|
+
context,
|
|
286
|
+
};
|
|
287
|
+
if (isUserError(error) && error.error) {
|
|
288
|
+
logData.originalError = {
|
|
289
|
+
name: error.error.name,
|
|
290
|
+
message: error.error.message,
|
|
291
|
+
stack: error.error.stack,
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
logger?.error?.("BillClaw error:", JSON.stringify(logData, null, 2));
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Get troubleshooting guide URL for error category
|
|
298
|
+
*/
|
|
299
|
+
export function getTroubleshootingUrl(category) {
|
|
300
|
+
const baseUrl = "https://github.com/fire-la/billclaw/blob/main/docs/troubleshooting.md";
|
|
301
|
+
const urls = {
|
|
302
|
+
[ErrorCategory.CONFIG]: `${baseUrl}#configuration-issues`,
|
|
303
|
+
[ErrorCategory.CREDENTIALS]: `${baseUrl}#credentials--authentication`,
|
|
304
|
+
[ErrorCategory.NETWORK]: `${baseUrl}#network-issues`,
|
|
305
|
+
[ErrorCategory.PLAID_API]: `${baseUrl}#plaid-integration`,
|
|
306
|
+
[ErrorCategory.PLAID_AUTH]: `${baseUrl}#credentials--authentication`,
|
|
307
|
+
[ErrorCategory.PLAID_ITEM]: `${baseUrl}#plaid-integration`,
|
|
308
|
+
[ErrorCategory.GMAIL_API]: `${baseUrl}#gmail-integration`,
|
|
309
|
+
[ErrorCategory.GMAIL_AUTH]: `${baseUrl}#credentials--authentication`,
|
|
310
|
+
[ErrorCategory.STORAGE]: `${baseUrl}#storage-issues`,
|
|
311
|
+
[ErrorCategory.FILE_SYSTEM]: `${baseUrl}#storage-issues`,
|
|
312
|
+
};
|
|
313
|
+
return urls[category] || baseUrl;
|
|
314
|
+
}
|
|
315
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/errors/errors.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/errors/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,aAAa,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/errors/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,aAAa,CAAA"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Beancount export functionality for BillClaw
|
|
3
|
+
*
|
|
4
|
+
* This module provides functionality to export BillClaw transactions
|
|
5
|
+
* to the Beancount plain text accounting format.
|
|
6
|
+
*
|
|
7
|
+
* Beancount format reference: https://beancount.github.io/docs/beancount_language_syntax.html
|
|
8
|
+
*/
|
|
9
|
+
import type { Transaction } from "../storage/transaction-storage.js";
|
|
10
|
+
import type { StorageConfig } from "../models/config.js";
|
|
11
|
+
/**
|
|
12
|
+
* Beancount transaction options
|
|
13
|
+
*/
|
|
14
|
+
export interface BeancountExportOptions {
|
|
15
|
+
accountId: string;
|
|
16
|
+
year: number;
|
|
17
|
+
month: number;
|
|
18
|
+
commodity?: string;
|
|
19
|
+
payeeAccount?: string;
|
|
20
|
+
tagAccounts?: Record<string, string>;
|
|
21
|
+
includeTags?: boolean;
|
|
22
|
+
dateFormat?: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Convert a BillClaw transaction to Beancount format
|
|
26
|
+
*/
|
|
27
|
+
export declare function transactionToBeancount(txn: Transaction, options: BeancountExportOptions): string;
|
|
28
|
+
/**
|
|
29
|
+
* Export transactions to Beancount format
|
|
30
|
+
*/
|
|
31
|
+
export declare function exportToBeancount(transactions: Transaction[], options: BeancountExportOptions): Promise<string>;
|
|
32
|
+
/**
|
|
33
|
+
* Export transactions from storage to Beancount format
|
|
34
|
+
*/
|
|
35
|
+
export declare function exportStorageToBeancount(accountId: string, year: number, month: number, storageConfig: StorageConfig, options?: Partial<BeancountExportOptions>): Promise<string>;
|
|
36
|
+
/**
|
|
37
|
+
* Get recommended account mappings for Beancount
|
|
38
|
+
*
|
|
39
|
+
* Returns a suggested mapping of BillClaw categories to Beancount accounts
|
|
40
|
+
*/
|
|
41
|
+
export declare function getBeancountAccountMappings(): Record<string, string>;
|
|
42
|
+
//# sourceMappingURL=beancount.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"beancount.d.ts","sourceRoot":"","sources":["../../src/exporters/beancount.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mCAAmC,CAAA;AACpE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAGxD;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACpC,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,WAAW,EAChB,OAAO,EAAE,sBAAsB,GAC9B,MAAM,CAiDR;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,YAAY,EAAE,WAAW,EAAE,EAC3B,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,MAAM,CAAC,CAoBjB;AAED;;GAEG;AACH,wBAAsB,wBAAwB,CAC5C,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,aAAa,EAC5B,OAAO,CAAC,EAAE,OAAO,CAAC,sBAAsB,CAAC,GACxC,OAAO,CAAC,MAAM,CAAC,CAgBjB;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAsDpE"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Beancount export functionality for BillClaw
|
|
3
|
+
*
|
|
4
|
+
* This module provides functionality to export BillClaw transactions
|
|
5
|
+
* to the Beancount plain text accounting format.
|
|
6
|
+
*
|
|
7
|
+
* Beancount format reference: https://beancount.github.io/docs/beancount_language_syntax.html
|
|
8
|
+
*/
|
|
9
|
+
import { readTransactions } from "../storage/transaction-storage.js";
|
|
10
|
+
/**
|
|
11
|
+
* Convert a BillClaw transaction to Beancount format
|
|
12
|
+
*/
|
|
13
|
+
export function transactionToBeancount(txn, options) {
|
|
14
|
+
const currency = options.commodity || "USD";
|
|
15
|
+
// Format date
|
|
16
|
+
const date = txn.date;
|
|
17
|
+
// Build payee line
|
|
18
|
+
const payee = txn.merchantName || "Unknown";
|
|
19
|
+
const narration = txn.category?.join(", ") || "";
|
|
20
|
+
// Build tags
|
|
21
|
+
let tags = "";
|
|
22
|
+
if (options.includeTags) {
|
|
23
|
+
const sourceTag = txn.paymentChannel === "email" ? "#gmail" : "#plaid";
|
|
24
|
+
tags = ` ${sourceTag}`;
|
|
25
|
+
if (txn.pending) {
|
|
26
|
+
tags += " #pending";
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
// Build transaction header
|
|
30
|
+
let output = `${date} * "${payee}"${tags}\n`;
|
|
31
|
+
// Add narration if present
|
|
32
|
+
if (narration) {
|
|
33
|
+
output += ` "${narration}"\n`;
|
|
34
|
+
}
|
|
35
|
+
// Determine target account based on category
|
|
36
|
+
const targetAccount = options.tagAccounts?.[txn.category?.[0] || ""] ||
|
|
37
|
+
options.payeeAccount ||
|
|
38
|
+
"Expenses:Unknown";
|
|
39
|
+
// Format amount (convert from cents to dollars)
|
|
40
|
+
const amount = (Math.abs(txn.amount) / 100).toFixed(2);
|
|
41
|
+
// Build postings
|
|
42
|
+
if (txn.amount < 0) {
|
|
43
|
+
// Expense/Outflow
|
|
44
|
+
output += ` ${targetAccount} ${amount} ${currency}\n`;
|
|
45
|
+
output += ` Assets:Bank:Checking\n`;
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
// Income/Inflow
|
|
49
|
+
output += ` Assets:Bank:Checking ${amount} ${currency}\n`;
|
|
50
|
+
output += ` ${targetAccount}\n`;
|
|
51
|
+
}
|
|
52
|
+
return output;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Export transactions to Beancount format
|
|
56
|
+
*/
|
|
57
|
+
export async function exportToBeancount(transactions, options) {
|
|
58
|
+
// Build Beancount file header (always include this)
|
|
59
|
+
let output = `;; Beancount export from BillClaw\n`;
|
|
60
|
+
output += `;; Account: ${options.accountId}\n`;
|
|
61
|
+
output += `;; Period: ${options.year}-${String(options.month).padStart(2, "0")}\n`;
|
|
62
|
+
output += `;; Exported: ${new Date().toISOString()}\n`;
|
|
63
|
+
output += "\n";
|
|
64
|
+
if (transactions.length === 0) {
|
|
65
|
+
output += "; No transactions found\n";
|
|
66
|
+
return output;
|
|
67
|
+
}
|
|
68
|
+
// Add each transaction
|
|
69
|
+
for (const txn of transactions) {
|
|
70
|
+
output += transactionToBeancount(txn, options);
|
|
71
|
+
output += "\n";
|
|
72
|
+
}
|
|
73
|
+
return output;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Export transactions from storage to Beancount format
|
|
77
|
+
*/
|
|
78
|
+
export async function exportStorageToBeancount(accountId, year, month, storageConfig, options) {
|
|
79
|
+
const transactions = await readTransactions(accountId, year, month, storageConfig);
|
|
80
|
+
const fullOptions = {
|
|
81
|
+
accountId,
|
|
82
|
+
year,
|
|
83
|
+
month,
|
|
84
|
+
...options,
|
|
85
|
+
};
|
|
86
|
+
return exportToBeancount(transactions, fullOptions);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Get recommended account mappings for Beancount
|
|
90
|
+
*
|
|
91
|
+
* Returns a suggested mapping of BillClaw categories to Beancount accounts
|
|
92
|
+
*/
|
|
93
|
+
export function getBeancountAccountMappings() {
|
|
94
|
+
return {
|
|
95
|
+
// Food & Dining
|
|
96
|
+
"Food and Drink": "Expenses:Food:Restaurants",
|
|
97
|
+
"Fast Food": "Expenses:Food:FastFood",
|
|
98
|
+
Groceries: "Expenses:Food:Groceries",
|
|
99
|
+
// Transportation
|
|
100
|
+
Travel: "Expenses:Travel",
|
|
101
|
+
Gasoline: "Expenses:Transport:Fuel",
|
|
102
|
+
Parking: "Expenses:Transport:Parking",
|
|
103
|
+
Taxi: "Expenses:Transport:Taxi",
|
|
104
|
+
"Ride Share": "Expenses:Transport:Rideshare",
|
|
105
|
+
"Public Transportation": "Expenses:Transport:Public",
|
|
106
|
+
// Shopping
|
|
107
|
+
Shopping: "Expenses:Shopping:General",
|
|
108
|
+
Electronics: "Expenses:Shopping:Electronics",
|
|
109
|
+
Clothing: "Expenses:Shopping:Clothing",
|
|
110
|
+
"Home Improvement": "Expenses:Home:Improvement",
|
|
111
|
+
// Entertainment
|
|
112
|
+
Entertainment: "Expenses:Entertainment:General",
|
|
113
|
+
Movies: "Expenses:Entertainment:Movies",
|
|
114
|
+
Music: "Expenses:Entertainment:Music",
|
|
115
|
+
Games: "Expenses:Entertainment:Games",
|
|
116
|
+
Sports: "Expenses:Entertainment:Sports",
|
|
117
|
+
// Bills & Utilities
|
|
118
|
+
Utilities: "Expenses:Utilities:General",
|
|
119
|
+
Electric: "Expenses:Utilities:Electric",
|
|
120
|
+
Gas: "Expenses:Utilities:Gas",
|
|
121
|
+
Water: "Expenses:Utilities:Water",
|
|
122
|
+
Internet: "Expenses:Utilities:Internet",
|
|
123
|
+
Phone: "Expenses:Utilities:Phone",
|
|
124
|
+
Subscription: "Expenses:Subscriptions",
|
|
125
|
+
// Health
|
|
126
|
+
Healthcare: "Expenses:Health:Medical",
|
|
127
|
+
Pharmacy: "Expenses:Health:Pharmacy",
|
|
128
|
+
Insurance: "Expenses:Insurance:Health",
|
|
129
|
+
// Financial
|
|
130
|
+
Finance: "Expenses:Financial:Fees",
|
|
131
|
+
"Bank Fee": "Expenses:Financial:BankFees",
|
|
132
|
+
Interest: "Expenses:Financial:Interest",
|
|
133
|
+
Transfer: "Expenses:Financial:Transfer",
|
|
134
|
+
// Income
|
|
135
|
+
Income: "Income:General",
|
|
136
|
+
Salary: "Income:Salary",
|
|
137
|
+
Refund: "Income:Refunds",
|
|
138
|
+
Investment: "Income:Investments",
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=beancount.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"beancount.js","sourceRoot":"","sources":["../../src/exporters/beancount.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/exporters/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,gBAAgB,CAAA;AAC9B,cAAc,aAAa,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/exporters/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,gBAAgB,CAAA;AAC9B,cAAc,aAAa,CAAA"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ledger (ledger-cli) export functionality for BillClaw
|
|
3
|
+
*
|
|
4
|
+
* This module provides functionality to export BillClaw transactions
|
|
5
|
+
* to the Ledger plain text accounting format.
|
|
6
|
+
*
|
|
7
|
+
* Ledger format reference: https://www.ledger-cli.org/3.0/doc/ledger3.html
|
|
8
|
+
*/
|
|
9
|
+
import type { Transaction } from "../storage/transaction-storage.js";
|
|
10
|
+
import type { StorageConfig } from "../models/config.js";
|
|
11
|
+
/**
|
|
12
|
+
* Ledger transaction options
|
|
13
|
+
*/
|
|
14
|
+
export interface LedgerExportOptions {
|
|
15
|
+
accountId: string;
|
|
16
|
+
year: number;
|
|
17
|
+
month: number;
|
|
18
|
+
commodity?: string;
|
|
19
|
+
payeeAccount?: string;
|
|
20
|
+
tagAccounts?: Record<string, string>;
|
|
21
|
+
includeTags?: boolean;
|
|
22
|
+
dateFormat?: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Convert a BillClaw transaction to Ledger format
|
|
26
|
+
*/
|
|
27
|
+
export declare function transactionToLedger(txn: Transaction, options: LedgerExportOptions): string;
|
|
28
|
+
/**
|
|
29
|
+
* Export transactions to Ledger format
|
|
30
|
+
*/
|
|
31
|
+
export declare function exportToLedger(transactions: Transaction[], options: LedgerExportOptions): Promise<string>;
|
|
32
|
+
/**
|
|
33
|
+
* Export transactions from storage to Ledger format
|
|
34
|
+
*/
|
|
35
|
+
export declare function exportStorageToLedger(accountId: string, year: number, month: number, storageConfig: StorageConfig, options?: Partial<LedgerExportOptions>): Promise<string>;
|
|
36
|
+
/**
|
|
37
|
+
* Get recommended account mappings for Ledger
|
|
38
|
+
*
|
|
39
|
+
* Returns a suggested mapping of BillClaw categories to Ledger accounts
|
|
40
|
+
*/
|
|
41
|
+
export declare function getLedgerAccountMappings(): Record<string, string>;
|
|
42
|
+
//# sourceMappingURL=ledger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ledger.d.ts","sourceRoot":"","sources":["../../src/exporters/ledger.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mCAAmC,CAAA;AACpE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAGxD;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACpC,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,WAAW,EAChB,OAAO,EAAE,mBAAmB,GAC3B,MAAM,CAgDR;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,YAAY,EAAE,WAAW,EAAE,EAC3B,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,MAAM,CAAC,CAmBjB;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CACzC,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,aAAa,EAC5B,OAAO,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC,GACrC,OAAO,CAAC,MAAM,CAAC,CAgBjB;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAsDjE"}
|