@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.
Files changed (139) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +109 -0
  3. package/dist/billclaw.d.ts +76 -0
  4. package/dist/billclaw.d.ts.map +1 -0
  5. package/dist/billclaw.js +205 -0
  6. package/dist/billclaw.js.map +1 -0
  7. package/dist/credentials/index.d.ts +8 -0
  8. package/dist/credentials/index.d.ts.map +1 -0
  9. package/dist/credentials/index.js +8 -0
  10. package/dist/credentials/index.js.map +1 -0
  11. package/dist/credentials/keychain.d.ts +92 -0
  12. package/dist/credentials/keychain.d.ts.map +1 -0
  13. package/dist/credentials/keychain.js +172 -0
  14. package/dist/credentials/keychain.js.map +1 -0
  15. package/dist/credentials/store.d.ts +76 -0
  16. package/dist/credentials/store.d.ts.map +1 -0
  17. package/dist/credentials/store.js +144 -0
  18. package/dist/credentials/store.js.map +1 -0
  19. package/dist/errors/errors.d.ts +92 -0
  20. package/dist/errors/errors.d.ts.map +1 -0
  21. package/dist/errors/errors.js +315 -0
  22. package/dist/errors/errors.js.map +1 -0
  23. package/dist/errors/index.d.ts +7 -0
  24. package/dist/errors/index.d.ts.map +1 -0
  25. package/dist/errors/index.js +7 -0
  26. package/dist/errors/index.js.map +1 -0
  27. package/dist/exporters/beancount.d.ts +42 -0
  28. package/dist/exporters/beancount.d.ts.map +1 -0
  29. package/dist/exporters/beancount.js +141 -0
  30. package/dist/exporters/beancount.js.map +1 -0
  31. package/dist/exporters/index.d.ts +8 -0
  32. package/dist/exporters/index.d.ts.map +1 -0
  33. package/dist/exporters/index.js +8 -0
  34. package/dist/exporters/index.js.map +1 -0
  35. package/dist/exporters/ledger.d.ts +42 -0
  36. package/dist/exporters/ledger.d.ts.map +1 -0
  37. package/dist/exporters/ledger.js +139 -0
  38. package/dist/exporters/ledger.js.map +1 -0
  39. package/dist/index.d.ts +23 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +34 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/models/config.d.ts +552 -0
  44. package/dist/models/config.d.ts.map +1 -0
  45. package/dist/models/config.js +168 -0
  46. package/dist/models/config.js.map +1 -0
  47. package/dist/models/index.d.ts +7 -0
  48. package/dist/models/index.d.ts.map +1 -0
  49. package/dist/models/index.js +8 -0
  50. package/dist/models/index.js.map +1 -0
  51. package/dist/runtime/index.d.ts +7 -0
  52. package/dist/runtime/index.d.ts.map +1 -0
  53. package/dist/runtime/index.js +7 -0
  54. package/dist/runtime/index.js.map +1 -0
  55. package/dist/runtime/types.d.ts +110 -0
  56. package/dist/runtime/types.d.ts.map +1 -0
  57. package/dist/runtime/types.js +85 -0
  58. package/dist/runtime/types.js.map +1 -0
  59. package/dist/security/audit.d.ts +148 -0
  60. package/dist/security/audit.d.ts.map +1 -0
  61. package/dist/security/audit.js +286 -0
  62. package/dist/security/audit.js.map +1 -0
  63. package/dist/security/index.d.ts +7 -0
  64. package/dist/security/index.d.ts.map +1 -0
  65. package/dist/security/index.js +7 -0
  66. package/dist/security/index.js.map +1 -0
  67. package/dist/services/event-emitter.d.ts +171 -0
  68. package/dist/services/event-emitter.d.ts.map +1 -0
  69. package/dist/services/event-emitter.js +287 -0
  70. package/dist/services/event-emitter.js.map +1 -0
  71. package/dist/services/index.d.ts +8 -0
  72. package/dist/services/index.d.ts.map +1 -0
  73. package/dist/services/index.js +8 -0
  74. package/dist/services/index.js.map +1 -0
  75. package/dist/sources/gmail/bill-recognizer.d.ts +71 -0
  76. package/dist/sources/gmail/bill-recognizer.d.ts.map +1 -0
  77. package/dist/sources/gmail/bill-recognizer.js +341 -0
  78. package/dist/sources/gmail/bill-recognizer.js.map +1 -0
  79. package/dist/sources/gmail/email-parser.d.ts +68 -0
  80. package/dist/sources/gmail/email-parser.d.ts.map +1 -0
  81. package/dist/sources/gmail/email-parser.js +238 -0
  82. package/dist/sources/gmail/email-parser.js.map +1 -0
  83. package/dist/sources/gmail/gmail-fetch.d.ts +54 -0
  84. package/dist/sources/gmail/gmail-fetch.d.ts.map +1 -0
  85. package/dist/sources/gmail/gmail-fetch.js +300 -0
  86. package/dist/sources/gmail/gmail-fetch.js.map +1 -0
  87. package/dist/sources/gmail/index.d.ts +7 -0
  88. package/dist/sources/gmail/index.d.ts.map +1 -0
  89. package/dist/sources/gmail/index.js +7 -0
  90. package/dist/sources/gmail/index.js.map +1 -0
  91. package/dist/sources/index.d.ts +8 -0
  92. package/dist/sources/index.d.ts.map +1 -0
  93. package/dist/sources/index.js +8 -0
  94. package/dist/sources/index.js.map +1 -0
  95. package/dist/sources/plaid/index.d.ts +7 -0
  96. package/dist/sources/plaid/index.d.ts.map +1 -0
  97. package/dist/sources/plaid/index.js +7 -0
  98. package/dist/sources/plaid/index.js.map +1 -0
  99. package/dist/sources/plaid/plaid-sync.d.ts +42 -0
  100. package/dist/sources/plaid/plaid-sync.d.ts.map +1 -0
  101. package/dist/sources/plaid/plaid-sync.js +182 -0
  102. package/dist/sources/plaid/plaid-sync.js.map +1 -0
  103. package/dist/storage/cache.d.ts +134 -0
  104. package/dist/storage/cache.d.ts.map +1 -0
  105. package/dist/storage/cache.js +239 -0
  106. package/dist/storage/cache.js.map +1 -0
  107. package/dist/storage/index.d.ts +11 -0
  108. package/dist/storage/index.d.ts.map +1 -0
  109. package/dist/storage/index.js +11 -0
  110. package/dist/storage/index.js.map +1 -0
  111. package/dist/storage/indexes.d.ts +136 -0
  112. package/dist/storage/indexes.d.ts.map +1 -0
  113. package/dist/storage/indexes.js +294 -0
  114. package/dist/storage/indexes.js.map +1 -0
  115. package/dist/storage/locking.d.ts +103 -0
  116. package/dist/storage/locking.d.ts.map +1 -0
  117. package/dist/storage/locking.js +158 -0
  118. package/dist/storage/locking.js.map +1 -0
  119. package/dist/storage/streaming.d.ts +102 -0
  120. package/dist/storage/streaming.d.ts.map +1 -0
  121. package/dist/storage/streaming.js +245 -0
  122. package/dist/storage/streaming.js.map +1 -0
  123. package/dist/storage/transaction-storage.d.ts +101 -0
  124. package/dist/storage/transaction-storage.d.ts.map +1 -0
  125. package/dist/storage/transaction-storage.js +193 -0
  126. package/dist/storage/transaction-storage.js.map +1 -0
  127. package/dist/sync/index.d.ts +7 -0
  128. package/dist/sync/index.d.ts.map +1 -0
  129. package/dist/sync/index.js +7 -0
  130. package/dist/sync/index.js.map +1 -0
  131. package/dist/sync/sync-service.d.ts +42 -0
  132. package/dist/sync/sync-service.d.ts.map +1 -0
  133. package/dist/sync/sync-service.js +112 -0
  134. package/dist/sync/sync-service.js.map +1 -0
  135. package/dist/test-fixtures.d.ts +38 -0
  136. package/dist/test-fixtures.d.ts.map +1 -0
  137. package/dist/test-fixtures.js +137 -0
  138. package/dist/test-fixtures.js.map +1 -0
  139. package/package.json +68 -0
@@ -0,0 +1,193 @@
1
+ /**
2
+ * Local file storage utilities for BillClaw data
3
+ */
4
+ import * as fs from "node:fs/promises";
5
+ import * as path from "node:path";
6
+ import * as os from "node:os";
7
+ /**
8
+ * Get the base storage directory
9
+ */
10
+ export async function getStorageDir(config) {
11
+ const storagePath = config?.path || "~/.billclaw";
12
+ const expandedPath = storagePath.replace(/^~/, os.homedir());
13
+ return expandedPath;
14
+ }
15
+ /**
16
+ * Initialize storage directory structure
17
+ */
18
+ export async function initializeStorage(config) {
19
+ const baseDir = await getStorageDir(config);
20
+ const directories = [
21
+ baseDir,
22
+ path.join(baseDir, "accounts"),
23
+ path.join(baseDir, "transactions"),
24
+ path.join(baseDir, "sync"),
25
+ ];
26
+ for (const dir of directories) {
27
+ try {
28
+ await fs.mkdir(dir, { recursive: true });
29
+ }
30
+ catch {
31
+ // Directory may already exist
32
+ }
33
+ }
34
+ }
35
+ /**
36
+ * Read account registry
37
+ */
38
+ export async function readAccountRegistry(config) {
39
+ const baseDir = await getStorageDir(config);
40
+ const filePath = path.join(baseDir, "accounts.json");
41
+ try {
42
+ const content = await fs.readFile(filePath, "utf-8");
43
+ return JSON.parse(content);
44
+ }
45
+ catch {
46
+ // File doesn't exist yet
47
+ return [];
48
+ }
49
+ }
50
+ /**
51
+ * Write account registry
52
+ */
53
+ export async function writeAccountRegistry(accounts, config) {
54
+ const baseDir = await getStorageDir(config);
55
+ const filePath = path.join(baseDir, "accounts.json");
56
+ await initializeStorage(config);
57
+ await fs.writeFile(filePath, JSON.stringify(accounts, null, 2), "utf-8");
58
+ }
59
+ /**
60
+ * Read transactions for an account and month
61
+ */
62
+ export async function readTransactions(accountId, year, month, config) {
63
+ const baseDir = await getStorageDir(config);
64
+ const monthStr = month.toString().padStart(2, "0");
65
+ const filePath = path.join(baseDir, "transactions", accountId, `${year}`, `${monthStr}.json`);
66
+ try {
67
+ const content = await fs.readFile(filePath, "utf-8");
68
+ return JSON.parse(content);
69
+ }
70
+ catch {
71
+ return [];
72
+ }
73
+ }
74
+ /**
75
+ * Write transactions for an account and month
76
+ * Uses atomic write (temp file + rename) for safety
77
+ */
78
+ export async function writeTransactions(accountId, year, month, transactions, config) {
79
+ const baseDir = await getStorageDir(config);
80
+ const monthStr = month.toString().padStart(2, "0");
81
+ const dirPath = path.join(baseDir, "transactions", accountId, `${year}`);
82
+ const filePath = path.join(dirPath, `${monthStr}.json`);
83
+ await fs.mkdir(dirPath, { recursive: true });
84
+ // Atomic write: write to temp file first, then rename
85
+ const tempPath = filePath + ".tmp";
86
+ await fs.writeFile(tempPath, JSON.stringify(transactions, null, 2), "utf-8");
87
+ await fs.rename(tempPath, filePath);
88
+ }
89
+ /**
90
+ * Append transactions to existing month file (with deduplication)
91
+ */
92
+ export async function appendTransactions(accountId, year, month, newTransactions, config) {
93
+ const existing = await readTransactions(accountId, year, month, config);
94
+ const existingIds = new Set(existing.map((t) => t.transactionId));
95
+ let added = 0;
96
+ let updated = 0;
97
+ for (const txn of newTransactions) {
98
+ if (existingIds.has(txn.transactionId)) {
99
+ // Update existing transaction
100
+ const index = existing.findIndex((t) => t.transactionId === txn.transactionId);
101
+ if (index !== -1) {
102
+ existing[index] = txn;
103
+ updated++;
104
+ }
105
+ }
106
+ else {
107
+ // Add new transaction
108
+ existing.push(txn);
109
+ existingIds.add(txn.transactionId);
110
+ added++;
111
+ }
112
+ }
113
+ // Sort by date descending
114
+ existing.sort((a, b) => b.date.localeCompare(a.date));
115
+ await writeTransactions(accountId, year, month, existing, config);
116
+ return { added, updated };
117
+ }
118
+ /**
119
+ * Read sync state for an account
120
+ */
121
+ export async function readSyncStates(accountId, config) {
122
+ const baseDir = await getStorageDir(config);
123
+ const dirPath = path.join(baseDir, "sync", accountId);
124
+ try {
125
+ const files = await fs.readdir(dirPath);
126
+ const states = [];
127
+ for (const file of files) {
128
+ if (!file.endsWith(".json"))
129
+ continue;
130
+ const filePath = path.join(dirPath, file);
131
+ const content = await fs.readFile(filePath, "utf-8");
132
+ states.push(JSON.parse(content));
133
+ }
134
+ return states.sort((a, b) => b.startedAt.localeCompare(a.startedAt));
135
+ }
136
+ catch {
137
+ return [];
138
+ }
139
+ }
140
+ /**
141
+ * Write sync state
142
+ */
143
+ export async function writeSyncState(state, config) {
144
+ const baseDir = await getStorageDir(config);
145
+ const dirPath = path.join(baseDir, "sync", state.accountId);
146
+ const filePath = path.join(dirPath, `${state.syncId}.json`);
147
+ await fs.mkdir(dirPath, { recursive: true });
148
+ await fs.writeFile(filePath, JSON.stringify(state, null, 2), "utf-8");
149
+ }
150
+ /**
151
+ * Read global cursor
152
+ */
153
+ export async function readGlobalCursor(config) {
154
+ const baseDir = await getStorageDir(config);
155
+ const filePath = path.join(baseDir, "cursor.json");
156
+ try {
157
+ const content = await fs.readFile(filePath, "utf-8");
158
+ return JSON.parse(content);
159
+ }
160
+ catch {
161
+ return null;
162
+ }
163
+ }
164
+ /**
165
+ * Write global cursor
166
+ */
167
+ export async function writeGlobalCursor(cursor, config) {
168
+ const baseDir = await getStorageDir(config);
169
+ const filePath = path.join(baseDir, "cursor.json");
170
+ await initializeStorage(config);
171
+ await fs.writeFile(filePath, JSON.stringify(cursor, null, 2), "utf-8");
172
+ }
173
+ /**
174
+ * Deduplicate transactions within a time window (24 hours)
175
+ */
176
+ export function deduplicateTransactions(transactions, windowHours = 24) {
177
+ const seen = new Set();
178
+ const windowStart = Date.now() - windowHours * 60 * 60 * 1000;
179
+ const result = [];
180
+ // Sort by date ascending
181
+ const sorted = [...transactions].sort((a, b) => a.date.localeCompare(b.date));
182
+ for (const txn of sorted) {
183
+ const key = `${txn.accountId}_${txn.plaidTransactionId}`;
184
+ const txnDate = new Date(txn.date).getTime();
185
+ // Only include if not seen, or outside deduplication window
186
+ if (!seen.has(key) || txnDate > windowStart) {
187
+ seen.add(key);
188
+ result.push(txn);
189
+ }
190
+ }
191
+ return result;
192
+ }
193
+ //# sourceMappingURL=transaction-storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transaction-storage.js","sourceRoot":"","sources":["../../src/storage/transaction-storage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Sync service for BillClaw
3
+ *
4
+ * @packageDocumentation
5
+ */
6
+ export * from "./sync-service.js";
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sync/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,mBAAmB,CAAA"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Sync service for BillClaw
3
+ *
4
+ * @packageDocumentation
5
+ */
6
+ export * from "./sync-service.js";
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sync/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,mBAAmB,CAAA"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Sync service for BillClaw - Framework-agnostic background sync logic
3
+ */
4
+ import type { AccountConfig } from "../models/config.js";
5
+ import type { Logger } from "../errors/errors.js";
6
+ export interface SyncResult {
7
+ accountId: string;
8
+ success: boolean;
9
+ transactionsAdded: number;
10
+ transactionsUpdated: number;
11
+ errors?: string[];
12
+ }
13
+ export interface SyncServiceState {
14
+ isRunning: boolean;
15
+ lastSync: string | null;
16
+ nextSync: string | null;
17
+ accountsSynced: number;
18
+ }
19
+ /**
20
+ * Sync function interface - adapters provide the actual sync implementation
21
+ */
22
+ export interface SyncProvider {
23
+ syncAccount(accountId: string): Promise<SyncResult>;
24
+ }
25
+ /**
26
+ * Calculate next sync time based on sync frequency
27
+ */
28
+ export declare function calculateNextSync(frequency: string, lastSync?: Date): Date;
29
+ /**
30
+ * Check if an account is due for sync
31
+ */
32
+ export declare function isDueForSync(account: AccountConfig): boolean;
33
+ /**
34
+ * Sync all accounts that are due for sync
35
+ *
36
+ * @param accounts - All configured accounts
37
+ * @param syncProvider - Provider that implements the actual sync logic
38
+ * @param logger - Logger for output
39
+ * @returns Array of sync results
40
+ */
41
+ export declare function syncDueAccounts(accounts: AccountConfig[], syncProvider: SyncProvider, logger: Logger): Promise<SyncResult[]>;
42
+ //# sourceMappingURL=sync-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-service.d.ts","sourceRoot":"","sources":["../../src/sync/sync-service.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACxD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAEjD,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,OAAO,CAAA;IAChB,iBAAiB,EAAE,MAAM,CAAA;IACzB,mBAAmB,EAAE,MAAM,CAAA;IAC3B,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,OAAO,CAAA;IAClB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,cAAc,EAAE,MAAM,CAAA;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAA;CACpD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,IAAI,GAAG,IAAI,CA+B1E;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAmB5D;AAkCD;;;;;;;GAOG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,aAAa,EAAE,EACzB,YAAY,EAAE,YAAY,EAC1B,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,UAAU,EAAE,CAAC,CAkCvB"}
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Sync service for BillClaw - Framework-agnostic background sync logic
3
+ */
4
+ /**
5
+ * Calculate next sync time based on sync frequency
6
+ */
7
+ export function calculateNextSync(frequency, lastSync) {
8
+ const now = new Date();
9
+ const base = lastSync || now;
10
+ switch (frequency) {
11
+ case "realtime":
12
+ // Webhook-based, no scheduled sync
13
+ return new Date(0);
14
+ case "hourly":
15
+ return new Date(base.getTime() + 60 * 60 * 1000);
16
+ case "daily":
17
+ // Next day at same time
18
+ const nextDay = new Date(base);
19
+ nextDay.setDate(nextDay.getDate() + 1);
20
+ return nextDay;
21
+ case "weekly":
22
+ // Next week on same day
23
+ const nextWeek = new Date(base);
24
+ nextWeek.setDate(nextWeek.getDate() + 7);
25
+ return nextWeek;
26
+ case "manual":
27
+ // No scheduled sync
28
+ return new Date(0);
29
+ default:
30
+ return new Date(base.getTime() + 24 * 60 * 60 * 1000);
31
+ }
32
+ }
33
+ /**
34
+ * Check if an account is due for sync
35
+ */
36
+ export function isDueForSync(account) {
37
+ if (!account.enabled || !account.lastSync) {
38
+ return true;
39
+ }
40
+ const lastSync = new Date(account.lastSync);
41
+ const nextSync = calculateNextSync(account.syncFrequency, lastSync);
42
+ // Manual accounts never sync automatically
43
+ if (account.syncFrequency === "manual") {
44
+ return false;
45
+ }
46
+ // Realtime accounts sync via webhook, not scheduled
47
+ if (account.syncFrequency === "realtime") {
48
+ return false;
49
+ }
50
+ return new Date() >= nextSync;
51
+ }
52
+ /**
53
+ * Sync a single account using the provided sync provider
54
+ */
55
+ async function syncAccount(accountId, syncProvider, logger) {
56
+ try {
57
+ const result = await syncProvider.syncAccount(accountId);
58
+ if (result.success) {
59
+ logger.info?.(`Sync completed for ${accountId}: ${result.transactionsAdded} added, ${result.transactionsUpdated} updated`);
60
+ }
61
+ else {
62
+ logger.error?.(`Sync failed for ${accountId}:`, result.errors || []);
63
+ }
64
+ return result;
65
+ }
66
+ catch (error) {
67
+ logger.error?.(`Error syncing ${accountId}:`, error);
68
+ return {
69
+ accountId,
70
+ success: false,
71
+ transactionsAdded: 0,
72
+ transactionsUpdated: 0,
73
+ errors: [error instanceof Error ? error.message : String(error)],
74
+ };
75
+ }
76
+ }
77
+ /**
78
+ * Sync all accounts that are due for sync
79
+ *
80
+ * @param accounts - All configured accounts
81
+ * @param syncProvider - Provider that implements the actual sync logic
82
+ * @param logger - Logger for output
83
+ * @returns Array of sync results
84
+ */
85
+ export async function syncDueAccounts(accounts, syncProvider, logger) {
86
+ logger.info?.("BillClaw sync service started");
87
+ // Filter for enabled accounts
88
+ const enabledAccounts = accounts.filter((acc) => acc.enabled);
89
+ if (enabledAccounts.length === 0) {
90
+ logger.info?.("No enabled accounts to sync");
91
+ return [];
92
+ }
93
+ logger.info?.(`Found ${enabledAccounts.length} enabled accounts to check`);
94
+ const results = [];
95
+ let syncedCount = 0;
96
+ for (const account of enabledAccounts) {
97
+ if (isDueForSync(account)) {
98
+ logger.info?.(`Syncing account: ${account.name} (${account.id})`);
99
+ const result = await syncAccount(account.id, syncProvider, logger);
100
+ results.push(result);
101
+ if (result.success) {
102
+ syncedCount++;
103
+ }
104
+ }
105
+ else {
106
+ logger.info?.(`Skipping ${account.name} (${account.id}): not due for sync`);
107
+ }
108
+ }
109
+ logger.info?.(`Sync service completed: ${syncedCount} accounts synced`);
110
+ return results;
111
+ }
112
+ //# sourceMappingURL=sync-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-service.js","sourceRoot":"","sources":["../../src/sync/sync-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Test fixtures for BillClaw
3
+ */
4
+ import type { AccountConfig, BillclawConfig } from "@firela/billclaw-core";
5
+ /**
6
+ * Sample Plaid transaction data (external format)
7
+ */
8
+ export interface PlaidTransactionData {
9
+ transaction_id: string;
10
+ account_id: string;
11
+ date: string;
12
+ amount: number;
13
+ iso_currency_code: string;
14
+ category?: string[];
15
+ merchant_name?: string;
16
+ payment_channel?: string;
17
+ pending?: boolean;
18
+ }
19
+ export declare const mockPlaidTransactions: PlaidTransactionData[];
20
+ /**
21
+ * Sample account configurations
22
+ */
23
+ export declare const mockAccounts: AccountConfig[];
24
+ /**
25
+ * Sample complete configuration
26
+ */
27
+ export declare const mockConfig: BillclawConfig;
28
+ /**
29
+ * Sample Gmail email content
30
+ */
31
+ export declare const mockGmailEmails: {
32
+ id: string;
33
+ from: string;
34
+ subject: string;
35
+ body: string;
36
+ date: string;
37
+ }[];
38
+ //# sourceMappingURL=test-fixtures.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-fixtures.d.ts","sourceRoot":"","sources":["../src/test-fixtures.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAE1E;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,cAAc,EAAE,MAAM,CAAA;IACtB,UAAU,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,iBAAiB,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;IACnB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,eAAO,MAAM,qBAAqB,EAAE,oBAAoB,EAuBvD,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,YAAY,EAAE,aAAa,EA8BvC,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,UAAU,EAAE,cAqCxB,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,eAAe;;;;;;GA8B3B,CAAA"}
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Test fixtures for BillClaw
3
+ */
4
+ export const mockPlaidTransactions = [
5
+ {
6
+ transaction_id: "plaid-txn-001",
7
+ account_id: "plaid-acct-123",
8
+ date: "2024-01-15",
9
+ amount: 125.5,
10
+ iso_currency_code: "USD",
11
+ category: ["Food", "Restaurants"],
12
+ merchant_name: "Test Restaurant",
13
+ payment_channel: "online",
14
+ pending: false,
15
+ },
16
+ {
17
+ transaction_id: "plaid-txn-002",
18
+ account_id: "plaid-acct-123",
19
+ date: "2024-01-16",
20
+ amount: 45.99,
21
+ iso_currency_code: "USD",
22
+ category: ["Shopping", "Electronics"],
23
+ merchant_name: "Tech Store",
24
+ payment_channel: "in store",
25
+ pending: true,
26
+ },
27
+ ];
28
+ /**
29
+ * Sample account configurations
30
+ */
31
+ export const mockAccounts = [
32
+ {
33
+ id: "plaid-sandbox-123",
34
+ type: "plaid",
35
+ name: "Test Bank Account",
36
+ enabled: true,
37
+ syncFrequency: "daily",
38
+ lastSync: "2024-01-16T10:30:00Z",
39
+ lastStatus: "success",
40
+ plaidItemId: "item-sandbox-123",
41
+ plaidAccessToken: "access-sandbox-test",
42
+ },
43
+ {
44
+ id: "gmail-bill-456",
45
+ type: "gmail",
46
+ name: "Gmail Bills",
47
+ enabled: true,
48
+ syncFrequency: "weekly",
49
+ lastSync: "2024-01-15T08:00:00Z",
50
+ lastStatus: "success",
51
+ gmailEmailAddress: "user@example.com",
52
+ gmailFilters: ["from:billing@*"],
53
+ },
54
+ {
55
+ id: "gocardless-sandbox-789",
56
+ type: "gocardless",
57
+ name: "European Bank",
58
+ enabled: false,
59
+ syncFrequency: "manual",
60
+ },
61
+ ];
62
+ /**
63
+ * Sample complete configuration
64
+ */
65
+ export const mockConfig = {
66
+ accounts: mockAccounts,
67
+ webhooks: [
68
+ {
69
+ enabled: true,
70
+ url: "https://example.com/webhook",
71
+ secret: "webhook-secret-key",
72
+ events: ["transaction.new", "sync.failed"],
73
+ retryPolicy: {
74
+ maxRetries: 3,
75
+ initialDelay: 1000,
76
+ maxDelay: 30000,
77
+ },
78
+ },
79
+ ],
80
+ storage: {
81
+ path: "~/.billclaw",
82
+ format: "json",
83
+ encryption: { enabled: false },
84
+ },
85
+ sync: {
86
+ defaultFrequency: "daily",
87
+ maxRetries: 3,
88
+ retryOnFailure: true,
89
+ },
90
+ plaid: {
91
+ clientId: "test-client-id",
92
+ secret: "test-secret",
93
+ environment: "sandbox",
94
+ },
95
+ gmail: {
96
+ senderWhitelist: ["billing@*"],
97
+ keywords: ["invoice", "receipt", "statement"],
98
+ confidenceThreshold: 0.5,
99
+ requireAmount: false,
100
+ requireDate: false,
101
+ },
102
+ };
103
+ /**
104
+ * Sample Gmail email content
105
+ */
106
+ export const mockGmailEmails = [
107
+ {
108
+ id: "gmail-msg-001",
109
+ from: "billing@company.com",
110
+ subject: "Your invoice for January",
111
+ body: `
112
+ Dear Customer,
113
+
114
+ Your invoice for January is ready.
115
+
116
+ Amount Due: $89.00
117
+ Due Date: January 31, 2024
118
+
119
+ Thank you for your business.
120
+ `,
121
+ date: "2024-01-15T10:00:00Z",
122
+ },
123
+ {
124
+ id: "gmail-msg-002",
125
+ from: "receipt@store.com",
126
+ subject: "Receipt for your purchase",
127
+ body: `
128
+ Thank you for your purchase!
129
+
130
+ Item: Widget Pro
131
+ Amount: $29.99
132
+ Date: 01/16/2024
133
+ `,
134
+ date: "2024-01-16T14:30:00Z",
135
+ },
136
+ ];
137
+ //# sourceMappingURL=test-fixtures.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-fixtures.js","sourceRoot":"","sources":["../src/test-fixtures.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,68 @@
1
+ {
2
+ "name": "@firela/billclaw-core",
3
+ "version": "0.1.3",
4
+ "description": "BillClaw Core - Framework-agnostic business logic for financial data import",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js",
12
+ "default": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist",
17
+ "README.md"
18
+ ],
19
+ "publishConfig": {
20
+ "access": "public"
21
+ },
22
+ "keywords": [
23
+ "financial-data",
24
+ "plaid",
25
+ "gocardless",
26
+ "banking",
27
+ "transactions",
28
+ "bills",
29
+ "data-sovereignty"
30
+ ],
31
+ "author": "fire-la",
32
+ "license": "MIT",
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "https://github.com/fire-la/billclaw.git",
36
+ "directory": "packages/core"
37
+ },
38
+ "devDependencies": {
39
+ "@types/node": "^25.2.0",
40
+ "@types/proper-lockfile": "^4.1.2",
41
+ "@vitest/coverage-v8": "^4.0.18",
42
+ "oxfmt": "^0.1.0",
43
+ "oxlint": "^0.15.0",
44
+ "typescript": "^5.8.0",
45
+ "vitest": "^3.0.0"
46
+ },
47
+ "optionalDependencies": {
48
+ "keytar": "^6.0.1"
49
+ },
50
+ "dependencies": {
51
+ "plaid": "^32.0.0",
52
+ "proper-lockfile": "^4.1.2",
53
+ "zod": "^3.25.0"
54
+ },
55
+ "engines": {
56
+ "node": ">=20.0.0"
57
+ },
58
+ "scripts": {
59
+ "build": "tsc",
60
+ "dev": "tsc --watch",
61
+ "test": "vitest",
62
+ "test:coverage": "vitest --coverage",
63
+ "lint": "oxlint",
64
+ "format": "oxfmt src/",
65
+ "format:write": "oxfmt -w src/",
66
+ "clean": "rm -rf dist"
67
+ }
68
+ }