@firela/billclaw-core 0.1.5 → 0.3.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/LICENSE +21 -0
- package/dist/billclaw.d.ts +8 -0
- package/dist/billclaw.d.ts.map +1 -1
- package/dist/billclaw.js +85 -3
- package/dist/billclaw.js.map +1 -1
- package/dist/config/config-manager.d.ts +127 -0
- package/dist/config/config-manager.d.ts.map +1 -0
- package/dist/config/config-manager.js +304 -0
- package/dist/config/config-manager.js.map +1 -0
- package/dist/config/env-loader.d.ts +33 -0
- package/dist/config/env-loader.d.ts.map +1 -0
- package/dist/config/env-loader.js +115 -0
- package/dist/config/env-loader.js.map +1 -0
- package/dist/config/index.d.ts +14 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +14 -0
- package/dist/config/index.js.map +1 -0
- package/dist/errors/errors.d.ts +110 -11
- package/dist/errors/errors.d.ts.map +1 -1
- package/dist/errors/errors.js +421 -122
- package/dist/errors/errors.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/models/config.d.ts +147 -0
- package/dist/models/config.d.ts.map +1 -1
- package/dist/models/config.js +36 -0
- package/dist/models/config.js.map +1 -1
- package/dist/oauth/index.d.ts +12 -0
- package/dist/oauth/index.d.ts.map +1 -0
- package/dist/oauth/index.js +13 -0
- package/dist/oauth/index.js.map +1 -0
- package/dist/oauth/providers/gmail.d.ts +63 -0
- package/dist/oauth/providers/gmail.d.ts.map +1 -0
- package/dist/oauth/providers/gmail.js +213 -0
- package/dist/oauth/providers/gmail.js.map +1 -0
- package/dist/oauth/providers/plaid.d.ts +40 -0
- package/dist/oauth/providers/plaid.d.ts.map +1 -0
- package/dist/oauth/providers/plaid.js +90 -0
- package/dist/oauth/providers/plaid.js.map +1 -0
- package/dist/oauth/types.d.ts +102 -0
- package/dist/oauth/types.d.ts.map +1 -0
- package/dist/oauth/types.js +10 -0
- package/dist/oauth/types.js.map +1 -0
- package/dist/runtime/types.d.ts +2 -0
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/runtime/types.js.map +1 -1
- package/dist/sources/gmail/gmail-fetch.d.ts +2 -2
- package/dist/sources/gmail/gmail-fetch.d.ts.map +1 -1
- package/dist/sources/gmail/gmail-fetch.js +34 -4
- package/dist/sources/gmail/gmail-fetch.js.map +1 -1
- package/dist/sources/plaid/plaid-sync.d.ts +2 -2
- package/dist/sources/plaid/plaid-sync.d.ts.map +1 -1
- package/dist/sources/plaid/plaid-sync.js +78 -18
- package/dist/sources/plaid/plaid-sync.js.map +1 -1
- package/dist/storage/locking.d.ts +4 -0
- package/dist/storage/locking.d.ts.map +1 -1
- package/dist/storage/locking.js +4 -0
- package/dist/storage/locking.js.map +1 -1
- package/dist/sync/sync-service.d.ts +2 -2
- package/dist/sync/sync-service.d.ts.map +1 -1
- package/dist/sync/sync-service.js +6 -1
- package/dist/sync/sync-service.js.map +1 -1
- package/dist/test-fixtures.d.ts.map +1 -1
- package/dist/test-fixtures.js +5 -0
- package/dist/test-fixtures.js.map +1 -1
- package/dist/webhooks/deduplication.d.ts +117 -0
- package/dist/webhooks/deduplication.d.ts.map +1 -0
- package/dist/webhooks/deduplication.js +258 -0
- package/dist/webhooks/deduplication.js.map +1 -0
- package/dist/webhooks/handlers/gmail.d.ts +39 -0
- package/dist/webhooks/handlers/gmail.d.ts.map +1 -0
- package/dist/webhooks/handlers/gmail.js +56 -0
- package/dist/webhooks/handlers/gmail.js.map +1 -0
- package/dist/webhooks/handlers/gocardless.d.ts +39 -0
- package/dist/webhooks/handlers/gocardless.d.ts.map +1 -0
- package/dist/webhooks/handlers/gocardless.js +73 -0
- package/dist/webhooks/handlers/gocardless.js.map +1 -0
- package/dist/webhooks/handlers/index.d.ts +10 -0
- package/dist/webhooks/handlers/index.d.ts.map +1 -0
- package/dist/webhooks/handlers/index.js +10 -0
- package/dist/webhooks/handlers/index.js.map +1 -0
- package/dist/webhooks/handlers/plaid.d.ts +73 -0
- package/dist/webhooks/handlers/plaid.d.ts.map +1 -0
- package/dist/webhooks/handlers/plaid.js +169 -0
- package/dist/webhooks/handlers/plaid.js.map +1 -0
- package/dist/webhooks/index.d.ts +15 -0
- package/dist/webhooks/index.d.ts.map +1 -0
- package/dist/webhooks/index.js +17 -0
- package/dist/webhooks/index.js.map +1 -0
- package/dist/webhooks/processor.d.ts +76 -0
- package/dist/webhooks/processor.d.ts.map +1 -0
- package/dist/webhooks/processor.js +116 -0
- package/dist/webhooks/processor.js.map +1 -0
- package/dist/webhooks/router.d.ts +80 -0
- package/dist/webhooks/router.d.ts.map +1 -0
- package/dist/webhooks/router.js +107 -0
- package/dist/webhooks/router.js.map +1 -0
- package/dist/webhooks/security.d.ts +90 -0
- package/dist/webhooks/security.d.ts.map +1 -0
- package/dist/webhooks/security.js +138 -0
- package/dist/webhooks/security.js.map +1 -0
- package/dist/webhooks/sync-rate-limiter.d.ts +138 -0
- package/dist/webhooks/sync-rate-limiter.d.ts.map +1 -0
- package/dist/webhooks/sync-rate-limiter.js +228 -0
- package/dist/webhooks/sync-rate-limiter.js.map +1 -0
- package/dist/webhooks/types.d.ts +140 -0
- package/dist/webhooks/types.d.ts.map +1 -0
- package/dist/webhooks/types.js +18 -0
- package/dist/webhooks/types.js.map +1 -0
- package/package.json +12 -12
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 fire-la
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/billclaw.d.ts
CHANGED
|
@@ -10,6 +10,14 @@ import type { Transaction, SyncState } from "./storage/transaction-storage.js";
|
|
|
10
10
|
import type { PlaidSyncResult } from "./sources/plaid/plaid-sync.js";
|
|
11
11
|
import type { GmailFetchResult } from "./sources/gmail/gmail-fetch.js";
|
|
12
12
|
import type { SyncResult } from "./sync/sync-service.js";
|
|
13
|
+
/**
|
|
14
|
+
* Check if an OAuth token is expired or about to expire
|
|
15
|
+
*
|
|
16
|
+
* @param expiryIso - Token expiry time as ISO string
|
|
17
|
+
* @param bufferSeconds - Buffer time in seconds before expiry (default: 300 = 5 minutes)
|
|
18
|
+
* @returns true if token is expired or will expire within buffer time
|
|
19
|
+
*/
|
|
20
|
+
export declare function isTokenExpired(expiryIso: string | undefined, bufferSeconds?: number): boolean;
|
|
13
21
|
/**
|
|
14
22
|
* BillClaw - Main class for financial data import
|
|
15
23
|
*/
|
package/dist/billclaw.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"billclaw.d.ts","sourceRoot":"","sources":["../src/billclaw.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"billclaw.d.ts","sourceRoot":"","sources":["../src/billclaw.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAa,MAAM,oBAAoB,CAAA;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACxE,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAA;AAC9E,OAAO,KAAK,EACV,eAAe,EAGhB,MAAM,+BAA+B,CAAA;AACtC,OAAO,KAAK,EACV,gBAAgB,EAGjB,MAAM,gCAAgC,CAAA;AACvC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAuBxD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,aAAa,GAAE,MAAY,GAC1B,OAAO,CAWT;AAED;;GAEG;AACH,qBAAa,QAAQ;IACnB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgB;gBAE5B,OAAO,EAAE,cAAc;IAInC;;OAEG;IACH,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED;;OAEG;IACH,IAAI,MAAM,IAAI,cAAc,CAE3B;IAID;;OAEG;IACG,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC;IAMxC;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAKnC;;OAEG;IACG,eAAe,CACnB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,WAAW,EAAE,CAAC;IAKzB;;OAEG;IACG,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAO5D;;OAEG;IACG,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAiEzD;;OAEG;IACG,eAAe,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;IAO9C;;OAEG;IACG,SAAS,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IAgClE;;OAEG;YACW,gBAAgB;IAe9B;;OAEG;IACG,SAAS,CACb,UAAU,CAAC,EAAE,MAAM,EAAE,EACrB,IAAI,GAAE,MAAW,GAChB,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAgH9B;;OAEG;YACW,gBAAgB;IAe9B;;OAEG;IACG,iBAAiB,CACrB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,GACrB,OAAO,CAAC,MAAM,CAAC;IAWlB;;OAEG;IACG,cAAc,CAClB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,GACrB,OAAO,CAAC,MAAM,CAAC;CAInB"}
|
package/dist/billclaw.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* This class provides the primary API for interacting with BillClaw.
|
|
5
5
|
* It is framework-agnostic and can be used by any adapter (CLI, OpenClaw, etc.).
|
|
6
6
|
*/
|
|
7
|
+
import { createUserError, ERROR_CODES, ErrorCategory } from "./errors/errors.js";
|
|
7
8
|
// Storage
|
|
8
9
|
import { readTransactions, readSyncStates, initializeStorage, } from "./storage/transaction-storage.js";
|
|
9
10
|
// Sync
|
|
@@ -13,6 +14,23 @@ import { syncPlaidAccounts } from "./sources/plaid/plaid-sync.js";
|
|
|
13
14
|
import { fetchGmailBills } from "./sources/gmail/gmail-fetch.js";
|
|
14
15
|
// Exporters
|
|
15
16
|
import { exportStorageToBeancount, exportStorageToLedger, } from "./exporters/index.js";
|
|
17
|
+
/**
|
|
18
|
+
* Check if an OAuth token is expired or about to expire
|
|
19
|
+
*
|
|
20
|
+
* @param expiryIso - Token expiry time as ISO string
|
|
21
|
+
* @param bufferSeconds - Buffer time in seconds before expiry (default: 300 = 5 minutes)
|
|
22
|
+
* @returns true if token is expired or will expire within buffer time
|
|
23
|
+
*/
|
|
24
|
+
export function isTokenExpired(expiryIso, bufferSeconds = 300) {
|
|
25
|
+
if (!expiryIso) {
|
|
26
|
+
// No expiry time means token doesn't expire
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
const expiryTime = new Date(expiryIso).getTime();
|
|
30
|
+
const now = Date.now();
|
|
31
|
+
const bufferMs = bufferSeconds * 1000;
|
|
32
|
+
return now >= expiryTime - bufferMs;
|
|
33
|
+
}
|
|
16
34
|
/**
|
|
17
35
|
* BillClaw - Main class for financial data import
|
|
18
36
|
*/
|
|
@@ -71,12 +89,21 @@ export class Billclaw {
|
|
|
71
89
|
const config = await this.context.config.getConfig();
|
|
72
90
|
const account = config.accounts.find((a) => a.id === accountId);
|
|
73
91
|
if (!account) {
|
|
92
|
+
const notFoundError = createUserError(ERROR_CODES.CONFIG_INVALID, ErrorCategory.CONFIG, "error", false, {
|
|
93
|
+
title: "Account Not Found",
|
|
94
|
+
message: `Account with ID "${accountId}" was not found in the configuration.`,
|
|
95
|
+
suggestions: [
|
|
96
|
+
"Verify the account ID is correct",
|
|
97
|
+
"Check that the account exists in your configuration",
|
|
98
|
+
"Run setup to add the account if needed",
|
|
99
|
+
],
|
|
100
|
+
}, [], { accountId });
|
|
74
101
|
return {
|
|
75
102
|
accountId,
|
|
76
103
|
success: false,
|
|
77
104
|
transactionsAdded: 0,
|
|
78
105
|
transactionsUpdated: 0,
|
|
79
|
-
errors: [
|
|
106
|
+
errors: [notFoundError],
|
|
80
107
|
};
|
|
81
108
|
}
|
|
82
109
|
switch (account.type) {
|
|
@@ -85,12 +112,20 @@ export class Billclaw {
|
|
|
85
112
|
case "gmail":
|
|
86
113
|
return await this.syncGmailAccount(account);
|
|
87
114
|
default:
|
|
115
|
+
const unsupportedTypeError = createUserError(ERROR_CODES.CONFIG_INVALID, ErrorCategory.CONFIG, "error", false, {
|
|
116
|
+
title: "Unsupported Account Type",
|
|
117
|
+
message: `Account type "${account.type}" is not supported.`,
|
|
118
|
+
suggestions: [
|
|
119
|
+
"Supported account types are: plaid, gmail",
|
|
120
|
+
"Update your configuration to use a supported account type",
|
|
121
|
+
],
|
|
122
|
+
}, [], { accountId });
|
|
88
123
|
return {
|
|
89
124
|
accountId,
|
|
90
125
|
success: false,
|
|
91
126
|
transactionsAdded: 0,
|
|
92
127
|
transactionsUpdated: 0,
|
|
93
|
-
errors: [
|
|
128
|
+
errors: [unsupportedTypeError],
|
|
94
129
|
};
|
|
95
130
|
}
|
|
96
131
|
}
|
|
@@ -167,7 +202,54 @@ export class Billclaw {
|
|
|
167
202
|
}
|
|
168
203
|
const results = [];
|
|
169
204
|
for (const account of accounts) {
|
|
170
|
-
|
|
205
|
+
// Get access token from account config
|
|
206
|
+
const accountConfig = config.accounts.find((a) => a.id === account.id);
|
|
207
|
+
const accessToken = accountConfig?.gmailAccessToken;
|
|
208
|
+
const tokenExpiry = accountConfig?.gmailTokenExpiry;
|
|
209
|
+
if (!accessToken) {
|
|
210
|
+
this.logger.warn?.(`No access token found for Gmail account ${account.id}. Please run OAuth setup first.`);
|
|
211
|
+
const noTokenError = createUserError(ERROR_CODES.GMAIL_AUTH_FAILED, ErrorCategory.GMAIL_AUTH, "error", true, {
|
|
212
|
+
title: "No OAuth Access Token Found",
|
|
213
|
+
message: `No OAuth access token was found for Gmail account ${account.id}.`,
|
|
214
|
+
suggestions: [
|
|
215
|
+
"Run OAuth setup first to authenticate with Gmail",
|
|
216
|
+
"Ensure the account is properly configured",
|
|
217
|
+
],
|
|
218
|
+
}, [{ type: "oauth_reauth", tool: "gmail_oauth", params: { accountId: account.id } }], { accountId: account.id });
|
|
219
|
+
results.push({
|
|
220
|
+
accountId: account.id,
|
|
221
|
+
success: false,
|
|
222
|
+
emailsProcessed: 0,
|
|
223
|
+
billsExtracted: 0,
|
|
224
|
+
transactionsAdded: 0,
|
|
225
|
+
transactionsUpdated: 0,
|
|
226
|
+
errors: [noTokenError],
|
|
227
|
+
});
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
// Check if token is expired (with 5 minute buffer)
|
|
231
|
+
if (isTokenExpired(tokenExpiry, 300)) {
|
|
232
|
+
this.logger.warn?.(`Access token expired for Gmail account ${account.id}. Please refresh the token.`);
|
|
233
|
+
const tokenExpiredError = createUserError(ERROR_CODES.GMAIL_AUTH_FAILED, ErrorCategory.GMAIL_AUTH, "error", true, {
|
|
234
|
+
title: "Gmail Access Token Expired",
|
|
235
|
+
message: `The access token for Gmail account ${account.id} has expired.`,
|
|
236
|
+
suggestions: [
|
|
237
|
+
"Refresh the token using OAuth refresh flow",
|
|
238
|
+
"Run setup again to re-authenticate with Gmail",
|
|
239
|
+
],
|
|
240
|
+
}, [{ type: "oauth_reauth", tool: "gmail_oauth", params: { accountId: account.id } }], { accountId: account.id });
|
|
241
|
+
results.push({
|
|
242
|
+
accountId: account.id,
|
|
243
|
+
success: false,
|
|
244
|
+
emailsProcessed: 0,
|
|
245
|
+
billsExtracted: 0,
|
|
246
|
+
transactionsAdded: 0,
|
|
247
|
+
transactionsUpdated: 0,
|
|
248
|
+
errors: [tokenExpiredError],
|
|
249
|
+
});
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
const result = await fetchGmailBills(account, days, gmailConfig, storageConfig, this.logger, accessToken);
|
|
171
253
|
results.push(result);
|
|
172
254
|
}
|
|
173
255
|
return results;
|
package/dist/billclaw.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"billclaw.js","sourceRoot":"","sources":["../src/billclaw.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"billclaw.js","sourceRoot":"","sources":["../src/billclaw.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified configuration manager for BillClaw
|
|
3
|
+
*
|
|
4
|
+
* Provides thread-safe configuration management with:
|
|
5
|
+
* - Singleton pattern
|
|
6
|
+
* - File locking for concurrent access
|
|
7
|
+
* - Hybrid caching (TTL + mtime validation)
|
|
8
|
+
* - Environment variable overrides
|
|
9
|
+
* - Schema validation
|
|
10
|
+
*
|
|
11
|
+
* @packageDocumentation
|
|
12
|
+
*/
|
|
13
|
+
import type { Logger } from "../errors/errors.js";
|
|
14
|
+
import { type BillclawConfig } from "../models/config.js";
|
|
15
|
+
import type { ConfigProvider, StorageConfig } from "../runtime/types.js";
|
|
16
|
+
/**
|
|
17
|
+
* ConfigManager options
|
|
18
|
+
*/
|
|
19
|
+
export interface ConfigManagerOptions {
|
|
20
|
+
/**
|
|
21
|
+
* Config file path (defaults to ~/.billclaw/config.json)
|
|
22
|
+
*/
|
|
23
|
+
configPath?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Cache TTL in milliseconds (defaults to 5 minutes)
|
|
26
|
+
*/
|
|
27
|
+
cacheTtl?: number;
|
|
28
|
+
/**
|
|
29
|
+
* Logger for debug output
|
|
30
|
+
*/
|
|
31
|
+
logger?: Logger;
|
|
32
|
+
/**
|
|
33
|
+
* Whether to enable environment variable overrides
|
|
34
|
+
*/
|
|
35
|
+
enableEnvOverrides?: boolean;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Unified configuration manager
|
|
39
|
+
*
|
|
40
|
+
* Implements the ConfigProvider interface with additional functionality
|
|
41
|
+
* for environment variable overrides and cache management.
|
|
42
|
+
*/
|
|
43
|
+
export declare class ConfigManager implements ConfigProvider {
|
|
44
|
+
private static instance;
|
|
45
|
+
private configPath;
|
|
46
|
+
private cache;
|
|
47
|
+
private cacheKey;
|
|
48
|
+
private cacheTtl;
|
|
49
|
+
private logger?;
|
|
50
|
+
private enableEnvOverrides;
|
|
51
|
+
private constructor();
|
|
52
|
+
/**
|
|
53
|
+
* Get the singleton ConfigManager instance
|
|
54
|
+
*
|
|
55
|
+
* @param options - Options (only applied on first call)
|
|
56
|
+
* @returns The singleton instance
|
|
57
|
+
*/
|
|
58
|
+
static getInstance(options?: ConfigManagerOptions): ConfigManager;
|
|
59
|
+
/**
|
|
60
|
+
* Reset the singleton instance (primarily for testing)
|
|
61
|
+
*/
|
|
62
|
+
static resetInstance(): void;
|
|
63
|
+
/**
|
|
64
|
+
* Get the full configuration
|
|
65
|
+
*
|
|
66
|
+
* Implements ConfigProvider interface with caching and mtime validation.
|
|
67
|
+
*/
|
|
68
|
+
getConfig(): Promise<BillclawConfig>;
|
|
69
|
+
/**
|
|
70
|
+
* Get effective configuration with environment variable overrides
|
|
71
|
+
*
|
|
72
|
+
* Returns config with env vars merged in (env vars take precedence).
|
|
73
|
+
*/
|
|
74
|
+
getEffectiveConfig(): Promise<BillclawConfig>;
|
|
75
|
+
/**
|
|
76
|
+
* Get storage configuration
|
|
77
|
+
*/
|
|
78
|
+
getStorageConfig(): Promise<StorageConfig>;
|
|
79
|
+
/**
|
|
80
|
+
* Update an account configuration
|
|
81
|
+
*/
|
|
82
|
+
updateAccount(accountId: string, updates: Partial<any>): Promise<void>;
|
|
83
|
+
/**
|
|
84
|
+
* Get an account by ID
|
|
85
|
+
*/
|
|
86
|
+
getAccount(accountId: string): Promise<any | null>;
|
|
87
|
+
/**
|
|
88
|
+
* Update configuration
|
|
89
|
+
*
|
|
90
|
+
* Merges updates with existing config and saves atomically with file locking.
|
|
91
|
+
*/
|
|
92
|
+
updateConfig(updates: Partial<BillclawConfig>): Promise<void>;
|
|
93
|
+
/**
|
|
94
|
+
* Get service-specific configuration
|
|
95
|
+
*
|
|
96
|
+
* @param service - Service name ('plaid' | 'gmail' | 'connect')
|
|
97
|
+
* @returns Service configuration with env overrides applied
|
|
98
|
+
*/
|
|
99
|
+
getServiceConfig(service: "plaid" | "gmail" | "connect"): Promise<any>;
|
|
100
|
+
/**
|
|
101
|
+
* Force reload configuration from disk
|
|
102
|
+
*
|
|
103
|
+
* Invalidates cache and reloads from file.
|
|
104
|
+
*/
|
|
105
|
+
reloadConfig(): Promise<void>;
|
|
106
|
+
/**
|
|
107
|
+
* Load configuration from file with validation
|
|
108
|
+
*
|
|
109
|
+
* Creates default config if file doesn't exist.
|
|
110
|
+
*/
|
|
111
|
+
private loadConfigFromFile;
|
|
112
|
+
/**
|
|
113
|
+
* Save configuration to file atomically with file locking
|
|
114
|
+
*/
|
|
115
|
+
private saveConfig;
|
|
116
|
+
/**
|
|
117
|
+
* Get default configuration
|
|
118
|
+
*/
|
|
119
|
+
private getDefaultConfig;
|
|
120
|
+
/**
|
|
121
|
+
* Deep merge two objects
|
|
122
|
+
*
|
|
123
|
+
* Source values override base values.
|
|
124
|
+
*/
|
|
125
|
+
private deepMerge;
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=config-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-manager.d.ts","sourceRoot":"","sources":["../../src/config/config-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAOH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AACjD,OAAO,EAAwB,KAAK,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAC/E,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAKxE;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IAEnB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IAEjB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IAEf;;OAEG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAC7B;AAkBD;;;;;GAKG;AACH,qBAAa,aAAc,YAAW,cAAc;IAClD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAe;IAEtC,OAAO,CAAC,UAAU,CAAQ;IAC1B,OAAO,CAAC,KAAK,CAAa;IAC1B,OAAO,CAAC,QAAQ,CAAQ;IACxB,OAAO,CAAC,QAAQ,CAAQ;IACxB,OAAO,CAAC,MAAM,CAAC,CAAQ;IACvB,OAAO,CAAC,kBAAkB,CAAS;IAEnC,OAAO;IAiBP;;;;;OAKG;IACH,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,aAAa;IAOjE;;OAEG;IACH,MAAM,CAAC,aAAa,IAAI,IAAI;IAO5B;;;;OAIG;IACG,SAAS,IAAI,OAAO,CAAC,cAAc,CAAC;IA6B1C;;;;OAIG;IACG,kBAAkB,IAAI,OAAO,CAAC,cAAc,CAAC;IAkCnD;;OAEG;IACG,gBAAgB,IAAI,OAAO,CAAC,aAAa,CAAC;IAKhD;;OAEG;IACG,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB5E;;OAEG;IACG,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;IAKxD;;;;OAIG;IACG,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAMnE;;;;;OAKG;IACG,gBAAgB,CACpB,OAAO,EAAE,OAAO,GAAG,OAAO,GAAG,SAAS,GACrC,OAAO,CAAC,GAAG,CAAC;IAYf;;;;OAIG;IACG,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAKnC;;;;OAIG;YACW,kBAAkB;IAwBhC;;OAEG;YACW,UAAU;IA+BxB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAyBxB;;;;OAIG;IACH,OAAO,CAAC,SAAS;CAqBlB"}
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified configuration manager for BillClaw
|
|
3
|
+
*
|
|
4
|
+
* Provides thread-safe configuration management with:
|
|
5
|
+
* - Singleton pattern
|
|
6
|
+
* - File locking for concurrent access
|
|
7
|
+
* - Hybrid caching (TTL + mtime validation)
|
|
8
|
+
* - Environment variable overrides
|
|
9
|
+
* - Schema validation
|
|
10
|
+
*
|
|
11
|
+
* @packageDocumentation
|
|
12
|
+
*/
|
|
13
|
+
import * as fs from "node:fs/promises";
|
|
14
|
+
import * as path from "node:path";
|
|
15
|
+
import * as os from "node:os";
|
|
16
|
+
import { z } from "zod";
|
|
17
|
+
import { BillclawConfigSchema } from "../models/config.js";
|
|
18
|
+
import { withLock } from "../storage/locking.js";
|
|
19
|
+
import { MemoryCache } from "../storage/cache.js";
|
|
20
|
+
import { loadEnvOverrides } from "./env-loader.js";
|
|
21
|
+
/**
|
|
22
|
+
* Default config path
|
|
23
|
+
*/
|
|
24
|
+
function getDefaultConfigPath() {
|
|
25
|
+
return path.join(os.homedir(), ".billclaw", "config.json");
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Unified configuration manager
|
|
29
|
+
*
|
|
30
|
+
* Implements the ConfigProvider interface with additional functionality
|
|
31
|
+
* for environment variable overrides and cache management.
|
|
32
|
+
*/
|
|
33
|
+
export class ConfigManager {
|
|
34
|
+
static instance;
|
|
35
|
+
configPath;
|
|
36
|
+
cache;
|
|
37
|
+
cacheKey;
|
|
38
|
+
cacheTtl;
|
|
39
|
+
logger;
|
|
40
|
+
enableEnvOverrides;
|
|
41
|
+
constructor(options = {}) {
|
|
42
|
+
this.configPath = options.configPath ?? getDefaultConfigPath();
|
|
43
|
+
this.cacheTtl = options.cacheTtl ?? 5 * 60 * 1000; // 5 minutes
|
|
44
|
+
this.logger = options.logger;
|
|
45
|
+
this.enableEnvOverrides = options.enableEnvOverrides ?? true;
|
|
46
|
+
// Create cache with configured TTL
|
|
47
|
+
this.cache = new MemoryCache({
|
|
48
|
+
defaultTtl: this.cacheTtl,
|
|
49
|
+
maxSize: 100,
|
|
50
|
+
logger: this.logger,
|
|
51
|
+
});
|
|
52
|
+
// Use config file path as cache key
|
|
53
|
+
this.cacheKey = `config:${this.configPath}`;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Get the singleton ConfigManager instance
|
|
57
|
+
*
|
|
58
|
+
* @param options - Options (only applied on first call)
|
|
59
|
+
* @returns The singleton instance
|
|
60
|
+
*/
|
|
61
|
+
static getInstance(options) {
|
|
62
|
+
if (!ConfigManager.instance) {
|
|
63
|
+
ConfigManager.instance = new ConfigManager(options);
|
|
64
|
+
}
|
|
65
|
+
return ConfigManager.instance;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Reset the singleton instance (primarily for testing)
|
|
69
|
+
*/
|
|
70
|
+
static resetInstance() {
|
|
71
|
+
if (ConfigManager.instance) {
|
|
72
|
+
ConfigManager.instance["cache"]?.destroy();
|
|
73
|
+
ConfigManager.instance = undefined;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Get the full configuration
|
|
78
|
+
*
|
|
79
|
+
* Implements ConfigProvider interface with caching and mtime validation.
|
|
80
|
+
*/
|
|
81
|
+
async getConfig() {
|
|
82
|
+
const cached = this.cache.get(this.cacheKey);
|
|
83
|
+
// Get current file mtime
|
|
84
|
+
let currentMtime = 0;
|
|
85
|
+
try {
|
|
86
|
+
const stats = await fs.stat(this.configPath);
|
|
87
|
+
currentMtime = stats.mtimeMs;
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
// File doesn't exist yet, will use default config
|
|
91
|
+
}
|
|
92
|
+
// Check if cache is valid (mtime matches)
|
|
93
|
+
if (cached && cached.mtime === currentMtime) {
|
|
94
|
+
this.logger?.debug("ConfigManager: using cached config");
|
|
95
|
+
return cached.config;
|
|
96
|
+
}
|
|
97
|
+
// Cache miss or invalidated, reload from file
|
|
98
|
+
this.logger?.debug("ConfigManager: reloading config from file");
|
|
99
|
+
const config = await this.loadConfigFromFile();
|
|
100
|
+
const envOverrides = this.enableEnvOverrides ? loadEnvOverrides() : {};
|
|
101
|
+
// Update cache with mtime
|
|
102
|
+
this.cache.set(this.cacheKey, { config, mtime: currentMtime, envOverrides }, this.cacheTtl);
|
|
103
|
+
return config;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Get effective configuration with environment variable overrides
|
|
107
|
+
*
|
|
108
|
+
* Returns config with env vars merged in (env vars take precedence).
|
|
109
|
+
*/
|
|
110
|
+
async getEffectiveConfig() {
|
|
111
|
+
const cached = this.cache.get(this.cacheKey);
|
|
112
|
+
// Get current file mtime
|
|
113
|
+
let currentMtime = 0;
|
|
114
|
+
try {
|
|
115
|
+
const stats = await fs.stat(this.configPath);
|
|
116
|
+
currentMtime = stats.mtimeMs;
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
// File doesn't exist yet
|
|
120
|
+
}
|
|
121
|
+
// Check if cache is valid
|
|
122
|
+
if (cached && cached.mtime === currentMtime) {
|
|
123
|
+
// Merge env overrides
|
|
124
|
+
if (this.enableEnvOverrides && Object.keys(cached.envOverrides).length > 0) {
|
|
125
|
+
return this.deepMerge(cached.config, cached.envOverrides);
|
|
126
|
+
}
|
|
127
|
+
return cached.config;
|
|
128
|
+
}
|
|
129
|
+
// Reload
|
|
130
|
+
const config = await this.loadConfigFromFile();
|
|
131
|
+
const envOverrides = this.enableEnvOverrides ? loadEnvOverrides() : {};
|
|
132
|
+
this.cache.set(this.cacheKey, { config, mtime: currentMtime, envOverrides }, this.cacheTtl);
|
|
133
|
+
// Return merged config
|
|
134
|
+
if (Object.keys(envOverrides).length > 0) {
|
|
135
|
+
return this.deepMerge(config, envOverrides);
|
|
136
|
+
}
|
|
137
|
+
return config;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Get storage configuration
|
|
141
|
+
*/
|
|
142
|
+
async getStorageConfig() {
|
|
143
|
+
const config = await this.getConfig();
|
|
144
|
+
return config.storage;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Update an account configuration
|
|
148
|
+
*/
|
|
149
|
+
async updateAccount(accountId, updates) {
|
|
150
|
+
const config = await this.getConfig();
|
|
151
|
+
const accountIndex = config.accounts.findIndex((a) => a.id === accountId);
|
|
152
|
+
if (accountIndex === -1) {
|
|
153
|
+
throw new Error(`Account ${accountId} not found`);
|
|
154
|
+
}
|
|
155
|
+
config.accounts[accountIndex] = {
|
|
156
|
+
...config.accounts[accountIndex],
|
|
157
|
+
...updates,
|
|
158
|
+
};
|
|
159
|
+
await this.saveConfig(config);
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Get an account by ID
|
|
163
|
+
*/
|
|
164
|
+
async getAccount(accountId) {
|
|
165
|
+
const config = await this.getConfig();
|
|
166
|
+
return config.accounts.find((a) => a.id === accountId) || null;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Update configuration
|
|
170
|
+
*
|
|
171
|
+
* Merges updates with existing config and saves atomically with file locking.
|
|
172
|
+
*/
|
|
173
|
+
async updateConfig(updates) {
|
|
174
|
+
const config = await this.getConfig();
|
|
175
|
+
const merged = this.deepMerge(config, updates);
|
|
176
|
+
await this.saveConfig(merged);
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Get service-specific configuration
|
|
180
|
+
*
|
|
181
|
+
* @param service - Service name ('plaid' | 'gmail' | 'connect')
|
|
182
|
+
* @returns Service configuration with env overrides applied
|
|
183
|
+
*/
|
|
184
|
+
async getServiceConfig(service) {
|
|
185
|
+
const effectiveConfig = await this.getEffectiveConfig();
|
|
186
|
+
const serviceConfig = effectiveConfig[service];
|
|
187
|
+
// For optional services, provide empty object if not configured
|
|
188
|
+
if (serviceConfig === undefined) {
|
|
189
|
+
return {};
|
|
190
|
+
}
|
|
191
|
+
return serviceConfig;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Force reload configuration from disk
|
|
195
|
+
*
|
|
196
|
+
* Invalidates cache and reloads from file.
|
|
197
|
+
*/
|
|
198
|
+
async reloadConfig() {
|
|
199
|
+
this.cache.delete(this.cacheKey);
|
|
200
|
+
await this.getConfig();
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Load configuration from file with validation
|
|
204
|
+
*
|
|
205
|
+
* Creates default config if file doesn't exist.
|
|
206
|
+
*/
|
|
207
|
+
async loadConfigFromFile() {
|
|
208
|
+
try {
|
|
209
|
+
const content = await fs.readFile(this.configPath, "utf-8");
|
|
210
|
+
const parsed = JSON.parse(content);
|
|
211
|
+
// Validate with Zod schema
|
|
212
|
+
const validated = BillclawConfigSchema.parse(parsed);
|
|
213
|
+
return validated;
|
|
214
|
+
}
|
|
215
|
+
catch (error) {
|
|
216
|
+
if (error.code === "ENOENT") {
|
|
217
|
+
// File doesn't exist, return default config
|
|
218
|
+
this.logger?.info("Config file not found, using defaults");
|
|
219
|
+
return this.getDefaultConfig();
|
|
220
|
+
}
|
|
221
|
+
if (error instanceof z.ZodError) {
|
|
222
|
+
this.logger?.error("Config validation failed:", error.errors);
|
|
223
|
+
throw new Error(`Invalid configuration: ${error.errors.map((e) => e.message).join(", ")}`);
|
|
224
|
+
}
|
|
225
|
+
throw error;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Save configuration to file atomically with file locking
|
|
230
|
+
*/
|
|
231
|
+
async saveConfig(config) {
|
|
232
|
+
const configDir = path.dirname(this.configPath);
|
|
233
|
+
// Ensure config directory exists
|
|
234
|
+
await fs.mkdir(configDir, { recursive: true });
|
|
235
|
+
// Ensure config file exists (required by proper-lockfile)
|
|
236
|
+
try {
|
|
237
|
+
await fs.access(this.configPath);
|
|
238
|
+
}
|
|
239
|
+
catch {
|
|
240
|
+
// File doesn't exist, create empty file
|
|
241
|
+
await fs.writeFile(this.configPath, JSON.stringify({}, null, 2), "utf-8");
|
|
242
|
+
}
|
|
243
|
+
await withLock(this.configPath, async () => {
|
|
244
|
+
// Atomic write: temp file + rename
|
|
245
|
+
const tmpPath = `${this.configPath}.tmp`;
|
|
246
|
+
await fs.writeFile(tmpPath, JSON.stringify(config, null, 2), "utf-8");
|
|
247
|
+
await fs.rename(tmpPath, this.configPath);
|
|
248
|
+
// Invalidate cache
|
|
249
|
+
this.cache.delete(this.cacheKey);
|
|
250
|
+
this.logger?.info(`Configuration saved to ${this.configPath}`);
|
|
251
|
+
}, { logger: this.logger });
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Get default configuration
|
|
255
|
+
*/
|
|
256
|
+
getDefaultConfig() {
|
|
257
|
+
return BillclawConfigSchema.parse({
|
|
258
|
+
version: 1,
|
|
259
|
+
connect: {
|
|
260
|
+
port: 4456,
|
|
261
|
+
host: "localhost",
|
|
262
|
+
},
|
|
263
|
+
plaid: {
|
|
264
|
+
environment: "sandbox",
|
|
265
|
+
},
|
|
266
|
+
storage: {
|
|
267
|
+
path: path.join(os.homedir(), ".billclaw"),
|
|
268
|
+
format: "json",
|
|
269
|
+
encryption: { enabled: false },
|
|
270
|
+
},
|
|
271
|
+
sync: {
|
|
272
|
+
defaultFrequency: "daily",
|
|
273
|
+
retryOnFailure: true,
|
|
274
|
+
maxRetries: 3,
|
|
275
|
+
},
|
|
276
|
+
accounts: [],
|
|
277
|
+
webhooks: [],
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Deep merge two objects
|
|
282
|
+
*
|
|
283
|
+
* Source values override base values.
|
|
284
|
+
*/
|
|
285
|
+
deepMerge(base, source) {
|
|
286
|
+
const result = { ...base };
|
|
287
|
+
for (const key of Object.keys(source)) {
|
|
288
|
+
if (source[key] !== null &&
|
|
289
|
+
typeof source[key] === "object" &&
|
|
290
|
+
!Array.isArray(source[key]) &&
|
|
291
|
+
key in result &&
|
|
292
|
+
result[key] !== null &&
|
|
293
|
+
typeof result[key] === "object" &&
|
|
294
|
+
!Array.isArray(result[key])) {
|
|
295
|
+
result[key] = this.deepMerge(result[key], source[key]);
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
result[key] = source[key];
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
return result;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
//# sourceMappingURL=config-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-manager.js","sourceRoot":"","sources":["../../src/config/config-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAA;AACtC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAA;AACjC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAA;AAC7B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,OAAO,EAAE,oBAAoB,EAAuB,MAAM,qBAAqB,CAAA;AAE/E,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAoClD;;GAEG;AACH,SAAS,oBAAoB;IAC3B,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,WAAW,EAAE,aAAa,CAAC,CAAA;AAC5D,CAAC;AAED;;;;;GAKG;AACH,MAAM,OAAO,aAAa;IAChB,MAAM,CAAC,QAAQ,CAAe;IAE9B,UAAU,CAAQ;IAClB,KAAK,CAAa;IAClB,QAAQ,CAAQ;IAChB,QAAQ,CAAQ;IAChB,MAAM,CAAS;IACf,kBAAkB,CAAS;IAEnC,YAAoB,UAAgC,EAAE;QACpD,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,oBAAoB,EAAE,CAAA;QAC9D,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAA,CAAC,YAAY;QAC9D,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAA;QAC5B,IAAI,CAAC,kBAAkB,GAAG,OAAO,CAAC,kBAAkB,IAAI,IAAI,CAAA;QAE5D,mCAAmC;QACnC,IAAI,CAAC,KAAK,GAAG,IAAI,WAAW,CAAC;YAC3B,UAAU,EAAE,IAAI,CAAC,QAAQ;YACzB,OAAO,EAAE,GAAG;YACZ,MAAM,EAAE,IAAI,CAAC,MAAM;SACpB,CAAC,CAAA;QAEF,oCAAoC;QACpC,IAAI,CAAC,QAAQ,GAAG,UAAU,IAAI,CAAC,UAAU,EAAE,CAAA;IAC7C,CAAC;IAED;;;;;OAKG;IACH,MAAM,CAAC,WAAW,CAAC,OAA8B;QAC/C,IAAI,CAAC,aAAa,CAAC,QAAQ,EAAE,CAAC;YAC5B,aAAa,CAAC,QAAQ,GAAG,IAAI,aAAa,CAAC,OAAO,CAAC,CAAA;QACrD,CAAC;QACD,OAAO,aAAa,CAAC,QAAQ,CAAA;IAC/B,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,aAAa;QAClB,IAAI,aAAa,CAAC,QAAQ,EAAE,CAAC;YAC3B,aAAa,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,CAAA;YAC1C,aAAa,CAAC,QAAQ,GAAG,SAAqC,CAAA;QAChE,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,SAAS;QACb,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAe,IAAI,CAAC,QAAQ,CAAC,CAAA;QAE1D,yBAAyB;QACzB,IAAI,YAAY,GAAG,CAAC,CAAA;QACpB,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;YAC5C,YAAY,GAAG,KAAK,CAAC,OAAO,CAAA;QAC9B,CAAC;QAAC,MAAM,CAAC;YACP,kDAAkD;QACpD,CAAC;QAED,0CAA0C;QAC1C,IAAI,MAAM,IAAI,MAAM,CAAC,KAAK,KAAK,YAAY,EAAE,CAAC;YAC5C,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,oCAAoC,CAAC,CAAA;YACxD,OAAO,MAAM,CAAC,MAAM,CAAA;QACtB,CAAC;QAED,8CAA8C;QAC9C,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,2CAA2C,CAAC,CAAA;QAC/D,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,kBAAkB,EAAE,CAAA;QAC9C,MAAM,YAAY,GAAG,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;QAEtE,0BAA0B;QAC1B,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAA;QAE3F,OAAO,MAAM,CAAA;IACf,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,kBAAkB;QACtB,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAe,IAAI,CAAC,QAAQ,CAAC,CAAA;QAE1D,yBAAyB;QACzB,IAAI,YAAY,GAAG,CAAC,CAAA;QACpB,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;YAC5C,YAAY,GAAG,KAAK,CAAC,OAAO,CAAA;QAC9B,CAAC;QAAC,MAAM,CAAC;YACP,yBAAyB;QAC3B,CAAC;QAED,0BAA0B;QAC1B,IAAI,MAAM,IAAI,MAAM,CAAC,KAAK,KAAK,YAAY,EAAE,CAAC;YAC5C,sBAAsB;YACtB,IAAI,IAAI,CAAC,kBAAkB,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC3E,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,YAAY,CAAC,CAAA;YAC3D,CAAC;YACD,OAAO,MAAM,CAAC,MAAM,CAAA;QACtB,CAAC;QAED,SAAS;QACT,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,kBAAkB,EAAE,CAAA;QAC9C,MAAM,YAAY,GAAG,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;QAEtE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAA;QAE3F,uBAAuB;QACvB,IAAI,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACzC,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,YAAY,CAAC,CAAA;QAC7C,CAAC;QACD,OAAO,MAAM,CAAA;IACf,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,gBAAgB;QACpB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,SAAS,EAAE,CAAA;QACrC,OAAO,MAAM,CAAC,OAAO,CAAA;IACvB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,aAAa,CAAC,SAAiB,EAAE,OAAqB;QAC1D,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,SAAS,EAAE,CAAA;QAErC,MAAM,YAAY,GAAG,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,SAAS,CAAC,CAAA;QACzE,IAAI,YAAY,KAAK,CAAC,CAAC,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,WAAW,SAAS,YAAY,CAAC,CAAA;QACnD,CAAC;QAED,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,GAAG;YAC9B,GAAG,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC;YAChC,GAAG,OAAO;SACX,CAAA;QAED,MAAM,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAA;IAC/B,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,UAAU,CAAC,SAAiB;QAChC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,SAAS,EAAE,CAAA;QACrC,OAAO,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,SAAS,CAAC,IAAI,IAAI,CAAA;IAChE,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,YAAY,CAAC,OAAgC;QACjD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,SAAS,EAAE,CAAA;QACrC,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QAC9C,MAAM,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAA;IAC/B,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,gBAAgB,CACpB,OAAsC;QAEtC,MAAM,eAAe,GAAG,MAAM,IAAI,CAAC,kBAAkB,EAAE,CAAA;QACvD,MAAM,aAAa,GAAG,eAAe,CAAC,OAAO,CAAC,CAAA;QAE9C,gEAAgE;QAChE,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;YAChC,OAAO,EAAE,CAAA;QACX,CAAC;QAED,OAAO,aAAa,CAAA;IACtB,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,YAAY;QAChB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QAChC,MAAM,IAAI,CAAC,SAAS,EAAE,CAAA;IACxB,CAAC;IAED;;;;OAIG;IACK,KAAK,CAAC,kBAAkB;QAC9B,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,CAAA;YAC3D,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;YAElC,2BAA2B;YAC3B,MAAM,SAAS,GAAG,oBAAoB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;YACpD,OAAO,SAAS,CAAA;QAClB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACvD,4CAA4C;gBAC5C,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,uCAAuC,CAAC,CAAA;gBAC1D,OAAO,IAAI,CAAC,gBAAgB,EAAE,CAAA;YAChC,CAAC;YAED,IAAI,KAAK,YAAY,CAAC,CAAC,QAAQ,EAAE,CAAC;gBAChC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,2BAA2B,EAAE,KAAK,CAAC,MAAM,CAAC,CAAA;gBAC7D,MAAM,IAAI,KAAK,CAAC,0BAA0B,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;YAC5F,CAAC;YAED,MAAM,KAAK,CAAA;QACb,CAAC;IACH,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,UAAU,CAAC,MAAsB;QAC7C,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;QAE/C,iCAAiC;QACjC,MAAM,EAAE,CAAC,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAE9C,0DAA0D;QAC1D,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;QAClC,CAAC;QAAC,MAAM,CAAC;YACP,wCAAwC;YACxC,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAA;QAC3E,CAAC;QAED,MAAM,QAAQ,CACZ,IAAI,CAAC,UAAU,EACf,KAAK,IAAI,EAAE;YACT,mCAAmC;YACnC,MAAM,OAAO,GAAG,GAAG,IAAI,CAAC,UAAU,MAAM,CAAA;YACxC,MAAM,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAA;YACrE,MAAM,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,UAAU,CAAC,CAAA;YAEzC,mBAAmB;YACnB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;YAEhC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,0BAA0B,IAAI,CAAC,UAAU,EAAE,CAAC,CAAA;QAChE,CAAC,EACD,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CACxB,CAAA;IACH,CAAC;IAED;;OAEG;IACK,gBAAgB;QACtB,OAAO,oBAAoB,CAAC,KAAK,CAAC;YAChC,OAAO,EAAE,CAAC;YACV,OAAO,EAAE;gBACP,IAAI,EAAE,IAAI;gBACV,IAAI,EAAE,WAAW;aAClB;YACD,KAAK,EAAE;gBACL,WAAW,EAAE,SAAS;aACvB;YACD,OAAO,EAAE;gBACP,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,WAAW,CAAC;gBAC1C,MAAM,EAAE,MAAM;gBACd,UAAU,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE;aAC/B;YACD,IAAI,EAAE;gBACJ,gBAAgB,EAAE,OAAO;gBACzB,cAAc,EAAE,IAAI;gBACpB,UAAU,EAAE,CAAC;aACd;YACD,QAAQ,EAAE,EAAE;YACZ,QAAQ,EAAE,EAAE;SACb,CAAC,CAAA;IACJ,CAAC;IAED;;;;OAIG;IACK,SAAS,CAAC,IAAS,EAAE,MAAW;QACtC,MAAM,MAAM,GAAG,EAAE,GAAG,IAAI,EAAE,CAAA;QAE1B,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YACtC,IACE,MAAM,CAAC,GAAG,CAAC,KAAK,IAAI;gBACpB,OAAO,MAAM,CAAC,GAAG,CAAC,KAAK,QAAQ;gBAC/B,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBAC3B,GAAG,IAAI,MAAM;gBACb,MAAM,CAAC,GAAG,CAAC,KAAK,IAAI;gBACpB,OAAO,MAAM,CAAC,GAAG,CAAC,KAAK,QAAQ;gBAC/B,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,EAC3B,CAAC;gBACD,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;YACxD,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAA;YAC3B,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAA;IACf,CAAC;CACF"}
|