@skillsmith/core 2.1.0 → 2.1.2
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/dist/.tsbuildinfo +1 -1
- package/dist/src/analysis/types.d.ts +2 -0
- package/dist/src/analysis/types.d.ts.map +1 -1
- package/dist/src/analysis/types.js +13 -1
- package/dist/src/analysis/types.js.map +1 -1
- package/dist/src/analytics/AnalyticsRepository.d.ts +4 -0
- package/dist/src/analytics/AnalyticsRepository.d.ts.map +1 -1
- package/dist/src/analytics/AnalyticsRepository.js +26 -44
- package/dist/src/analytics/AnalyticsRepository.js.map +1 -1
- package/dist/src/analytics/schema.d.ts +1 -1
- package/dist/src/analytics/schema.d.ts.map +1 -1
- package/dist/src/analytics/schema.js +68 -0
- package/dist/src/analytics/schema.js.map +1 -1
- package/dist/src/api/client.d.ts +33 -29
- package/dist/src/api/client.d.ts.map +1 -1
- package/dist/src/api/client.js +15 -10
- package/dist/src/api/client.js.map +1 -1
- package/dist/src/billing/BillingService.d.ts +139 -0
- package/dist/src/billing/BillingService.d.ts.map +1 -0
- package/dist/src/billing/BillingService.js +393 -0
- package/dist/src/billing/BillingService.js.map +1 -0
- package/dist/src/billing/GDPRComplianceService.d.ts +176 -0
- package/dist/src/billing/GDPRComplianceService.d.ts.map +1 -0
- package/dist/src/billing/GDPRComplianceService.js +361 -0
- package/dist/src/billing/GDPRComplianceService.js.map +1 -0
- package/dist/src/billing/StripeClient.d.ts +177 -0
- package/dist/src/billing/StripeClient.d.ts.map +1 -0
- package/dist/src/billing/StripeClient.js +462 -0
- package/dist/src/billing/StripeClient.js.map +1 -0
- package/dist/src/billing/StripeReconciliationJob.d.ts +95 -0
- package/dist/src/billing/StripeReconciliationJob.d.ts.map +1 -0
- package/dist/src/billing/StripeReconciliationJob.js +405 -0
- package/dist/src/billing/StripeReconciliationJob.js.map +1 -0
- package/dist/src/billing/StripeWebhookHandler.d.ts +92 -0
- package/dist/src/billing/StripeWebhookHandler.d.ts.map +1 -0
- package/dist/src/billing/StripeWebhookHandler.js +409 -0
- package/dist/src/billing/StripeWebhookHandler.js.map +1 -0
- package/dist/src/billing/index.d.ts +18 -0
- package/dist/src/billing/index.d.ts.map +1 -0
- package/dist/src/billing/index.js +19 -0
- package/dist/src/billing/index.js.map +1 -0
- package/dist/src/billing/types.d.ts +266 -0
- package/dist/src/billing/types.d.ts.map +1 -0
- package/dist/src/billing/types.js +23 -0
- package/dist/src/billing/types.js.map +1 -0
- package/dist/src/embeddings/hnsw-store.d.ts +568 -0
- package/dist/src/embeddings/hnsw-store.d.ts.map +1 -0
- package/dist/src/embeddings/hnsw-store.js +805 -0
- package/dist/src/embeddings/hnsw-store.js.map +1 -0
- package/dist/src/embeddings/index.d.ts +2 -0
- package/dist/src/embeddings/index.d.ts.map +1 -1
- package/dist/src/embeddings/index.js +2 -0
- package/dist/src/embeddings/index.js.map +1 -1
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +2 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/learning/PatternStore.d.ts +457 -0
- package/dist/src/learning/PatternStore.d.ts.map +1 -0
- package/dist/src/learning/PatternStore.js +893 -0
- package/dist/src/learning/PatternStore.js.map +1 -0
- package/dist/src/learning/ReasoningBankIntegration.d.ts +403 -0
- package/dist/src/learning/ReasoningBankIntegration.d.ts.map +1 -0
- package/dist/src/learning/ReasoningBankIntegration.js +627 -0
- package/dist/src/learning/ReasoningBankIntegration.js.map +1 -0
- package/dist/src/learning/index.d.ts +15 -0
- package/dist/src/learning/index.d.ts.map +1 -0
- package/dist/src/learning/index.js +15 -0
- package/dist/src/learning/index.js.map +1 -0
- package/dist/src/routing/SONARouter.d.ts +154 -0
- package/dist/src/routing/SONARouter.d.ts.map +1 -0
- package/dist/src/routing/SONARouter.js +679 -0
- package/dist/src/routing/SONARouter.js.map +1 -0
- package/dist/src/routing/index.d.ts +9 -0
- package/dist/src/routing/index.d.ts.map +1 -0
- package/dist/src/routing/index.js +10 -0
- package/dist/src/routing/index.js.map +1 -0
- package/dist/src/routing/types.d.ts +331 -0
- package/dist/src/routing/types.d.ts.map +1 -0
- package/dist/src/routing/types.js +203 -0
- package/dist/src/routing/types.js.map +1 -0
- package/dist/src/scripts/__tests__/scan-imported-skills.test.js +5 -0
- package/dist/src/scripts/__tests__/scan-imported-skills.test.js.map +1 -1
- package/dist/src/security/SkillSandbox.d.ts +156 -0
- package/dist/src/security/SkillSandbox.d.ts.map +1 -0
- package/dist/src/security/SkillSandbox.js +303 -0
- package/dist/src/security/SkillSandbox.js.map +1 -0
- package/dist/src/security/index.d.ts +3 -1
- package/dist/src/security/index.d.ts.map +1 -1
- package/dist/src/security/index.js +5 -1
- package/dist/src/security/index.js.map +1 -1
- package/dist/src/security/rate-limiter/presets.d.ts +12 -0
- package/dist/src/security/rate-limiter/presets.d.ts.map +1 -1
- package/dist/src/security/rate-limiter/presets.js +12 -0
- package/dist/src/security/rate-limiter/presets.js.map +1 -1
- package/dist/src/security/sanitization.d.ts +85 -0
- package/dist/src/security/sanitization.d.ts.map +1 -1
- package/dist/src/security/sanitization.js +133 -0
- package/dist/src/security/sanitization.js.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.d.ts +23 -0
- package/dist/src/security/scanner/SecurityScanner.d.ts.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.js +232 -28
- package/dist/src/security/scanner/SecurityScanner.js.map +1 -1
- package/dist/src/security/scanner/patterns.d.ts +13 -0
- package/dist/src/security/scanner/patterns.d.ts.map +1 -1
- package/dist/src/security/scanner/patterns.js +51 -0
- package/dist/src/security/scanner/patterns.js.map +1 -1
- package/dist/src/security/scanner/types.d.ts +13 -1
- package/dist/src/security/scanner/types.d.ts.map +1 -1
- package/dist/src/security/scanner/weights.d.ts.map +1 -1
- package/dist/src/security/scanner/weights.js +1 -0
- package/dist/src/security/scanner/weights.js.map +1 -1
- package/dist/src/session/SessionManager.d.ts +7 -0
- package/dist/src/session/SessionManager.d.ts.map +1 -1
- package/dist/src/session/SessionManager.js +117 -10
- package/dist/src/session/SessionManager.js.map +1 -1
- package/dist/src/sync/SyncEngine.d.ts.map +1 -1
- package/dist/src/sync/SyncEngine.js +52 -32
- package/dist/src/sync/SyncEngine.js.map +1 -1
- package/dist/src/testing/MultiLLMProvider.d.ts +374 -0
- package/dist/src/testing/MultiLLMProvider.d.ts.map +1 -0
- package/dist/src/testing/MultiLLMProvider.js +720 -0
- package/dist/src/testing/MultiLLMProvider.js.map +1 -0
- package/dist/src/testing/index.d.ts +8 -0
- package/dist/src/testing/index.d.ts.map +1 -0
- package/dist/src/testing/index.js +9 -0
- package/dist/src/testing/index.js.map +1 -0
- package/dist/src/types.d.ts +3 -0
- package/dist/src/types.d.ts.map +1 -1
- package/dist/tests/SecurityScanner.test.js +337 -1
- package/dist/tests/SecurityScanner.test.js.map +1 -1
- package/dist/tests/billing/BillingService.test.d.ts +7 -0
- package/dist/tests/billing/BillingService.test.d.ts.map +1 -0
- package/dist/tests/billing/BillingService.test.js +168 -0
- package/dist/tests/billing/BillingService.test.js.map +1 -0
- package/dist/tests/billing/GDPRCompliance.test.d.ts +7 -0
- package/dist/tests/billing/GDPRCompliance.test.d.ts.map +1 -0
- package/dist/tests/billing/GDPRCompliance.test.js +195 -0
- package/dist/tests/billing/GDPRCompliance.test.js.map +1 -0
- package/dist/tests/billing/StripeReconciliation.test.d.ts +7 -0
- package/dist/tests/billing/StripeReconciliation.test.d.ts.map +1 -0
- package/dist/tests/billing/StripeReconciliation.test.js +266 -0
- package/dist/tests/billing/StripeReconciliation.test.js.map +1 -0
- package/dist/tests/billing/stripe-validators.test.d.ts +7 -0
- package/dist/tests/billing/stripe-validators.test.d.ts.map +1 -0
- package/dist/tests/billing/stripe-validators.test.js +107 -0
- package/dist/tests/billing/stripe-validators.test.js.map +1 -0
- package/dist/tests/embeddings/hnsw-store.test.d.ts +7 -0
- package/dist/tests/embeddings/hnsw-store.test.d.ts.map +1 -0
- package/dist/tests/embeddings/hnsw-store.test.js +295 -0
- package/dist/tests/embeddings/hnsw-store.test.js.map +1 -0
- package/dist/tests/integration/neural/e2e-learning.test.d.ts +17 -0
- package/dist/tests/integration/neural/e2e-learning.test.d.ts.map +1 -0
- package/dist/tests/integration/neural/e2e-learning.test.js +238 -0
- package/dist/tests/integration/neural/e2e-learning.test.js.map +1 -0
- package/dist/tests/integration/neural/helpers.d.ts +132 -0
- package/dist/tests/integration/neural/helpers.d.ts.map +1 -0
- package/dist/tests/integration/neural/helpers.js +287 -0
- package/dist/tests/integration/neural/helpers.js.map +1 -0
- package/dist/tests/integration/neural/personalization.test.d.ts +21 -0
- package/dist/tests/integration/neural/personalization.test.d.ts.map +1 -0
- package/dist/tests/integration/neural/personalization.test.js +304 -0
- package/dist/tests/integration/neural/personalization.test.js.map +1 -0
- package/dist/tests/integration/neural/preference-learner.test.d.ts +23 -0
- package/dist/tests/integration/neural/preference-learner.test.d.ts.map +1 -0
- package/dist/tests/integration/neural/preference-learner.test.js +289 -0
- package/dist/tests/integration/neural/preference-learner.test.js.map +1 -0
- package/dist/tests/integration/neural/privacy.test.d.ts +19 -0
- package/dist/tests/integration/neural/privacy.test.d.ts.map +1 -0
- package/dist/tests/integration/neural/privacy.test.js +249 -0
- package/dist/tests/integration/neural/privacy.test.js.map +1 -0
- package/dist/tests/integration/neural/setup.d.ts +175 -0
- package/dist/tests/integration/neural/setup.d.ts.map +1 -0
- package/dist/tests/integration/neural/setup.js +487 -0
- package/dist/tests/integration/neural/setup.js.map +1 -0
- package/dist/tests/integration/neural/signal-collection.test.d.ts +21 -0
- package/dist/tests/integration/neural/signal-collection.test.d.ts.map +1 -0
- package/dist/tests/integration/neural/signal-collection.test.js +232 -0
- package/dist/tests/integration/neural/signal-collection.test.js.map +1 -0
- package/dist/tests/learning/PatternStore.test.d.ts +8 -0
- package/dist/tests/learning/PatternStore.test.d.ts.map +1 -0
- package/dist/tests/learning/PatternStore.test.js +589 -0
- package/dist/tests/learning/PatternStore.test.js.map +1 -0
- package/dist/tests/learning/ReasoningBankIntegration.test.d.ts +8 -0
- package/dist/tests/learning/ReasoningBankIntegration.test.d.ts.map +1 -0
- package/dist/tests/learning/ReasoningBankIntegration.test.js +269 -0
- package/dist/tests/learning/ReasoningBankIntegration.test.js.map +1 -0
- package/dist/tests/routing/SONARouter.test.d.ts +8 -0
- package/dist/tests/routing/SONARouter.test.d.ts.map +1 -0
- package/dist/tests/routing/SONARouter.test.js +400 -0
- package/dist/tests/routing/SONARouter.test.js.map +1 -0
- package/dist/tests/security/ContinuousSecurity.test.js +10 -12
- package/dist/tests/security/ContinuousSecurity.test.js.map +1 -1
- package/dist/tests/security/SkillSandbox.test.d.ts +8 -0
- package/dist/tests/security/SkillSandbox.test.d.ts.map +1 -0
- package/dist/tests/security/SkillSandbox.test.js +321 -0
- package/dist/tests/security/SkillSandbox.test.js.map +1 -0
- package/dist/tests/sync/SyncEngine.test.js +4 -2
- package/dist/tests/sync/SyncEngine.test.js.map +1 -1
- package/dist/tests/testing/MultiLLMProvider.test.d.ts +14 -0
- package/dist/tests/testing/MultiLLMProvider.test.d.ts.map +1 -0
- package/dist/tests/testing/MultiLLMProvider.test.js +438 -0
- package/dist/tests/testing/MultiLLMProvider.test.js.map +1 -0
- package/package.json +16 -3
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SMI-1069: Stripe Reconciliation Job
|
|
3
|
+
*
|
|
4
|
+
* Periodically reconciles local subscription and invoice data with Stripe.
|
|
5
|
+
* Identifies and reports discrepancies to ensure data consistency.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Subscription status sync
|
|
9
|
+
* - Invoice status verification
|
|
10
|
+
* - Missing data detection
|
|
11
|
+
* - Automatic correction (optional)
|
|
12
|
+
* - Detailed reporting
|
|
13
|
+
*/
|
|
14
|
+
import type { Database as BetterSqliteDatabase } from 'better-sqlite3';
|
|
15
|
+
import type { StripeClient } from './StripeClient.js';
|
|
16
|
+
export interface StripeReconciliationJobConfig {
|
|
17
|
+
/**
|
|
18
|
+
* StripeClient for API calls
|
|
19
|
+
*/
|
|
20
|
+
stripeClient: StripeClient;
|
|
21
|
+
/**
|
|
22
|
+
* Database connection
|
|
23
|
+
*/
|
|
24
|
+
db: BetterSqliteDatabase;
|
|
25
|
+
/**
|
|
26
|
+
* Whether to automatically fix discrepancies
|
|
27
|
+
* @default false
|
|
28
|
+
*/
|
|
29
|
+
autoFix?: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Maximum subscriptions to process per run
|
|
32
|
+
* @default 100
|
|
33
|
+
*/
|
|
34
|
+
batchSize?: number;
|
|
35
|
+
}
|
|
36
|
+
export type DiscrepancyType = 'status_mismatch' | 'missing_local' | 'missing_stripe' | 'tier_mismatch' | 'seat_count_mismatch' | 'period_mismatch' | 'invoice_status_mismatch' | 'invoice_amount_mismatch';
|
|
37
|
+
export interface Discrepancy {
|
|
38
|
+
type: DiscrepancyType;
|
|
39
|
+
entityType: 'subscription' | 'invoice';
|
|
40
|
+
entityId: string;
|
|
41
|
+
stripeId: string;
|
|
42
|
+
localValue: string | number | null;
|
|
43
|
+
stripeValue: string | number | null;
|
|
44
|
+
description: string;
|
|
45
|
+
fixed: boolean;
|
|
46
|
+
}
|
|
47
|
+
export interface ReconciliationResult {
|
|
48
|
+
success: boolean;
|
|
49
|
+
startedAt: string;
|
|
50
|
+
completedAt: string;
|
|
51
|
+
durationMs: number;
|
|
52
|
+
stats: {
|
|
53
|
+
subscriptionsChecked: number;
|
|
54
|
+
invoicesChecked: number;
|
|
55
|
+
discrepanciesFound: number;
|
|
56
|
+
discrepanciesFixed: number;
|
|
57
|
+
};
|
|
58
|
+
discrepancies: Discrepancy[];
|
|
59
|
+
errors: string[];
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Stripe Reconciliation Job
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```typescript
|
|
66
|
+
* const job = new StripeReconciliationJob({
|
|
67
|
+
* stripeClient,
|
|
68
|
+
* db,
|
|
69
|
+
* autoFix: true,
|
|
70
|
+
* });
|
|
71
|
+
*
|
|
72
|
+
* // Run reconciliation
|
|
73
|
+
* const result = await job.run();
|
|
74
|
+
* console.log(`Found ${result.discrepancies.length} discrepancies`);
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
export declare class StripeReconciliationJob {
|
|
78
|
+
private readonly stripe;
|
|
79
|
+
private readonly db;
|
|
80
|
+
private readonly autoFix;
|
|
81
|
+
private readonly batchSize;
|
|
82
|
+
constructor(config: StripeReconciliationJobConfig);
|
|
83
|
+
/**
|
|
84
|
+
* Run the reconciliation job
|
|
85
|
+
*/
|
|
86
|
+
run(): Promise<ReconciliationResult>;
|
|
87
|
+
private getLocalSubscriptions;
|
|
88
|
+
private reconcileSubscription;
|
|
89
|
+
private getLocalInvoices;
|
|
90
|
+
private reconcileInvoice;
|
|
91
|
+
private fixDiscrepancy;
|
|
92
|
+
private fixSubscriptionDiscrepancy;
|
|
93
|
+
private fixInvoiceDiscrepancy;
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=StripeReconciliationJob.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StripeReconciliationJob.d.ts","sourceRoot":"","sources":["../../../src/billing/StripeReconciliationJob.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,QAAQ,IAAI,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AAGtE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AASrD,MAAM,WAAW,6BAA6B;IAC5C;;OAEG;IACH,YAAY,EAAE,YAAY,CAAA;IAE1B;;OAEG;IACH,EAAE,EAAE,oBAAoB,CAAA;IAExB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IAEjB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAMD,MAAM,MAAM,eAAe,GACvB,iBAAiB,GACjB,eAAe,GACf,gBAAgB,GAChB,eAAe,GACf,qBAAqB,GACrB,iBAAiB,GACjB,yBAAyB,GACzB,yBAAyB,CAAA;AAE7B,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,eAAe,CAAA;IACrB,UAAU,EAAE,cAAc,GAAG,SAAS,CAAA;IACtC,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IAClC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IACnC,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,EAAE,OAAO,CAAA;CACf;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,OAAO,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;IAClB,KAAK,EAAE;QACL,oBAAoB,EAAE,MAAM,CAAA;QAC5B,eAAe,EAAE,MAAM,CAAA;QACvB,kBAAkB,EAAE,MAAM,CAAA;QAC1B,kBAAkB,EAAE,MAAM,CAAA;KAC3B,CAAA;IACD,aAAa,EAAE,WAAW,EAAE,CAAA;IAC5B,MAAM,EAAE,MAAM,EAAE,CAAA;CACjB;AAMD;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,uBAAuB;IAClC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;IACrC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAsB;IACzC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAQ;gBAEtB,MAAM,EAAE,6BAA6B;IAgBjD;;OAEG;IACG,GAAG,IAAI,OAAO,CAAC,oBAAoB,CAAC;IAuF1C,OAAO,CAAC,qBAAqB;YAoBf,qBAAqB;IA0EnC,OAAO,CAAC,gBAAgB;YAgBV,gBAAgB;IAyD9B,OAAO,CAAC,cAAc;IAmBtB,OAAO,CAAC,0BAA0B;IA+ClC,OAAO,CAAC,qBAAqB;CA0B9B"}
|
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SMI-1069: Stripe Reconciliation Job
|
|
3
|
+
*
|
|
4
|
+
* Periodically reconciles local subscription and invoice data with Stripe.
|
|
5
|
+
* Identifies and reports discrepancies to ensure data consistency.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Subscription status sync
|
|
9
|
+
* - Invoice status verification
|
|
10
|
+
* - Missing data detection
|
|
11
|
+
* - Automatic correction (optional)
|
|
12
|
+
* - Detailed reporting
|
|
13
|
+
*/
|
|
14
|
+
import { createLogger } from '../utils/logger.js';
|
|
15
|
+
const logger = createLogger('StripeReconciliation');
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// StripeReconciliationJob Class
|
|
18
|
+
// ============================================================================
|
|
19
|
+
/**
|
|
20
|
+
* Stripe Reconciliation Job
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```typescript
|
|
24
|
+
* const job = new StripeReconciliationJob({
|
|
25
|
+
* stripeClient,
|
|
26
|
+
* db,
|
|
27
|
+
* autoFix: true,
|
|
28
|
+
* });
|
|
29
|
+
*
|
|
30
|
+
* // Run reconciliation
|
|
31
|
+
* const result = await job.run();
|
|
32
|
+
* console.log(`Found ${result.discrepancies.length} discrepancies`);
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export class StripeReconciliationJob {
|
|
36
|
+
stripe;
|
|
37
|
+
db;
|
|
38
|
+
autoFix;
|
|
39
|
+
batchSize;
|
|
40
|
+
constructor(config) {
|
|
41
|
+
this.stripe = config.stripeClient;
|
|
42
|
+
this.db = config.db;
|
|
43
|
+
this.autoFix = config.autoFix ?? false;
|
|
44
|
+
this.batchSize = config.batchSize ?? 100;
|
|
45
|
+
logger.info('Stripe reconciliation job initialized', {
|
|
46
|
+
autoFix: this.autoFix,
|
|
47
|
+
batchSize: this.batchSize,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
// ==========================================================================
|
|
51
|
+
// Main Entry Point
|
|
52
|
+
// ==========================================================================
|
|
53
|
+
/**
|
|
54
|
+
* Run the reconciliation job
|
|
55
|
+
*/
|
|
56
|
+
async run() {
|
|
57
|
+
const startedAt = new Date();
|
|
58
|
+
const discrepancies = [];
|
|
59
|
+
const errors = [];
|
|
60
|
+
let subscriptionsChecked = 0;
|
|
61
|
+
let invoicesChecked = 0;
|
|
62
|
+
let discrepanciesFixed = 0;
|
|
63
|
+
logger.info('Starting Stripe reconciliation job');
|
|
64
|
+
try {
|
|
65
|
+
// 1. Get all local subscriptions with Stripe IDs
|
|
66
|
+
const localSubscriptions = this.getLocalSubscriptions();
|
|
67
|
+
subscriptionsChecked = localSubscriptions.length;
|
|
68
|
+
// 2. Reconcile each subscription
|
|
69
|
+
for (const local of localSubscriptions) {
|
|
70
|
+
try {
|
|
71
|
+
const subDiscrepancies = await this.reconcileSubscription(local);
|
|
72
|
+
discrepancies.push(...subDiscrepancies);
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
76
|
+
errors.push(`Subscription ${local.stripeSubscriptionId}: ${errorMsg}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// 3. Reconcile invoices
|
|
80
|
+
const localInvoices = this.getLocalInvoices();
|
|
81
|
+
invoicesChecked = localInvoices.length;
|
|
82
|
+
for (const invoice of localInvoices) {
|
|
83
|
+
try {
|
|
84
|
+
const invDiscrepancies = await this.reconcileInvoice(invoice);
|
|
85
|
+
discrepancies.push(...invDiscrepancies);
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
89
|
+
errors.push(`Invoice ${invoice.stripeInvoiceId}: ${errorMsg}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
// 4. Apply fixes if autoFix is enabled
|
|
93
|
+
if (this.autoFix) {
|
|
94
|
+
for (const discrepancy of discrepancies) {
|
|
95
|
+
if (this.fixDiscrepancy(discrepancy)) {
|
|
96
|
+
discrepancy.fixed = true;
|
|
97
|
+
discrepanciesFixed++;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
104
|
+
errors.push(`Job failed: ${errorMsg}`);
|
|
105
|
+
logger.error('Reconciliation job failed', undefined, { error: errorMsg });
|
|
106
|
+
}
|
|
107
|
+
const completedAt = new Date();
|
|
108
|
+
const result = {
|
|
109
|
+
success: errors.length === 0,
|
|
110
|
+
startedAt: startedAt.toISOString(),
|
|
111
|
+
completedAt: completedAt.toISOString(),
|
|
112
|
+
durationMs: completedAt.getTime() - startedAt.getTime(),
|
|
113
|
+
stats: {
|
|
114
|
+
subscriptionsChecked,
|
|
115
|
+
invoicesChecked,
|
|
116
|
+
discrepanciesFound: discrepancies.length,
|
|
117
|
+
discrepanciesFixed,
|
|
118
|
+
},
|
|
119
|
+
discrepancies,
|
|
120
|
+
errors,
|
|
121
|
+
};
|
|
122
|
+
logger.info('Stripe reconciliation job completed', {
|
|
123
|
+
success: result.success,
|
|
124
|
+
subscriptionsChecked,
|
|
125
|
+
invoicesChecked,
|
|
126
|
+
discrepanciesFound: discrepancies.length,
|
|
127
|
+
discrepanciesFixed,
|
|
128
|
+
durationMs: result.durationMs,
|
|
129
|
+
});
|
|
130
|
+
return result;
|
|
131
|
+
}
|
|
132
|
+
// ==========================================================================
|
|
133
|
+
// Subscription Reconciliation
|
|
134
|
+
// ==========================================================================
|
|
135
|
+
getLocalSubscriptions() {
|
|
136
|
+
return this.db
|
|
137
|
+
.prepare(`SELECT
|
|
138
|
+
id,
|
|
139
|
+
customer_id as customerId,
|
|
140
|
+
stripe_subscription_id as stripeSubscriptionId,
|
|
141
|
+
stripe_customer_id as stripeCustomerId,
|
|
142
|
+
tier,
|
|
143
|
+
status,
|
|
144
|
+
seat_count as seatCount,
|
|
145
|
+
current_period_start as currentPeriodStart,
|
|
146
|
+
current_period_end as currentPeriodEnd
|
|
147
|
+
FROM user_subscriptions
|
|
148
|
+
WHERE stripe_subscription_id IS NOT NULL
|
|
149
|
+
LIMIT ?`)
|
|
150
|
+
.all(this.batchSize);
|
|
151
|
+
}
|
|
152
|
+
async reconcileSubscription(local) {
|
|
153
|
+
const discrepancies = [];
|
|
154
|
+
// Fetch from Stripe
|
|
155
|
+
const stripeSubscription = await this.stripe.getSubscription(local.stripeSubscriptionId);
|
|
156
|
+
if (!stripeSubscription) {
|
|
157
|
+
discrepancies.push({
|
|
158
|
+
type: 'missing_stripe',
|
|
159
|
+
entityType: 'subscription',
|
|
160
|
+
entityId: local.id,
|
|
161
|
+
stripeId: local.stripeSubscriptionId,
|
|
162
|
+
localValue: local.status,
|
|
163
|
+
stripeValue: null,
|
|
164
|
+
description: 'Subscription exists locally but not in Stripe',
|
|
165
|
+
fixed: false,
|
|
166
|
+
});
|
|
167
|
+
return discrepancies;
|
|
168
|
+
}
|
|
169
|
+
// Compare status
|
|
170
|
+
const stripeStatus = mapStripeStatus(stripeSubscription.status);
|
|
171
|
+
if (local.status !== stripeStatus) {
|
|
172
|
+
discrepancies.push({
|
|
173
|
+
type: 'status_mismatch',
|
|
174
|
+
entityType: 'subscription',
|
|
175
|
+
entityId: local.id,
|
|
176
|
+
stripeId: local.stripeSubscriptionId,
|
|
177
|
+
localValue: local.status,
|
|
178
|
+
stripeValue: stripeStatus,
|
|
179
|
+
description: `Status mismatch: local=${local.status}, stripe=${stripeStatus}`,
|
|
180
|
+
fixed: false,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
// Compare tier (from metadata)
|
|
184
|
+
const stripeTier = stripeSubscription.metadata?.tier;
|
|
185
|
+
if (stripeTier && local.tier !== stripeTier) {
|
|
186
|
+
discrepancies.push({
|
|
187
|
+
type: 'tier_mismatch',
|
|
188
|
+
entityType: 'subscription',
|
|
189
|
+
entityId: local.id,
|
|
190
|
+
stripeId: local.stripeSubscriptionId,
|
|
191
|
+
localValue: local.tier,
|
|
192
|
+
stripeValue: stripeTier,
|
|
193
|
+
description: `Tier mismatch: local=${local.tier}, stripe=${stripeTier}`,
|
|
194
|
+
fixed: false,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
// Compare seat count
|
|
198
|
+
const stripeQuantity = stripeSubscription.items.data[0]?.quantity ?? 1;
|
|
199
|
+
if (local.seatCount !== stripeQuantity) {
|
|
200
|
+
discrepancies.push({
|
|
201
|
+
type: 'seat_count_mismatch',
|
|
202
|
+
entityType: 'subscription',
|
|
203
|
+
entityId: local.id,
|
|
204
|
+
stripeId: local.stripeSubscriptionId,
|
|
205
|
+
localValue: local.seatCount,
|
|
206
|
+
stripeValue: stripeQuantity,
|
|
207
|
+
description: `Seat count mismatch: local=${local.seatCount}, stripe=${stripeQuantity}`,
|
|
208
|
+
fixed: false,
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
return discrepancies;
|
|
212
|
+
}
|
|
213
|
+
// ==========================================================================
|
|
214
|
+
// Invoice Reconciliation
|
|
215
|
+
// ==========================================================================
|
|
216
|
+
getLocalInvoices() {
|
|
217
|
+
return this.db
|
|
218
|
+
.prepare(`SELECT
|
|
219
|
+
id,
|
|
220
|
+
customer_id as customerId,
|
|
221
|
+
stripe_invoice_id as stripeInvoiceId,
|
|
222
|
+
amount_cents as amountCents,
|
|
223
|
+
status
|
|
224
|
+
FROM invoices
|
|
225
|
+
WHERE stripe_invoice_id IS NOT NULL
|
|
226
|
+
LIMIT ?`)
|
|
227
|
+
.all(this.batchSize);
|
|
228
|
+
}
|
|
229
|
+
async reconcileInvoice(local) {
|
|
230
|
+
const discrepancies = [];
|
|
231
|
+
// Fetch from Stripe
|
|
232
|
+
const stripeInvoice = await this.stripe.getInvoice(local.stripeInvoiceId);
|
|
233
|
+
if (!stripeInvoice) {
|
|
234
|
+
discrepancies.push({
|
|
235
|
+
type: 'missing_stripe',
|
|
236
|
+
entityType: 'invoice',
|
|
237
|
+
entityId: local.id,
|
|
238
|
+
stripeId: local.stripeInvoiceId,
|
|
239
|
+
localValue: local.status,
|
|
240
|
+
stripeValue: null,
|
|
241
|
+
description: 'Invoice exists locally but not in Stripe',
|
|
242
|
+
fixed: false,
|
|
243
|
+
});
|
|
244
|
+
return discrepancies;
|
|
245
|
+
}
|
|
246
|
+
// Compare status
|
|
247
|
+
const stripeStatus = mapInvoiceStatus(stripeInvoice.status);
|
|
248
|
+
if (local.status !== stripeStatus) {
|
|
249
|
+
discrepancies.push({
|
|
250
|
+
type: 'invoice_status_mismatch',
|
|
251
|
+
entityType: 'invoice',
|
|
252
|
+
entityId: local.id,
|
|
253
|
+
stripeId: local.stripeInvoiceId,
|
|
254
|
+
localValue: local.status,
|
|
255
|
+
stripeValue: stripeStatus,
|
|
256
|
+
description: `Invoice status mismatch: local=${local.status}, stripe=${stripeStatus}`,
|
|
257
|
+
fixed: false,
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
// Compare amount
|
|
261
|
+
const stripeAmount = stripeInvoice.amount_paid ?? stripeInvoice.amount_due;
|
|
262
|
+
if (local.amountCents !== stripeAmount) {
|
|
263
|
+
discrepancies.push({
|
|
264
|
+
type: 'invoice_amount_mismatch',
|
|
265
|
+
entityType: 'invoice',
|
|
266
|
+
entityId: local.id,
|
|
267
|
+
stripeId: local.stripeInvoiceId,
|
|
268
|
+
localValue: local.amountCents,
|
|
269
|
+
stripeValue: stripeAmount,
|
|
270
|
+
description: `Invoice amount mismatch: local=${local.amountCents}, stripe=${stripeAmount}`,
|
|
271
|
+
fixed: false,
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
return discrepancies;
|
|
275
|
+
}
|
|
276
|
+
// ==========================================================================
|
|
277
|
+
// Fix Discrepancies
|
|
278
|
+
// ==========================================================================
|
|
279
|
+
fixDiscrepancy(discrepancy) {
|
|
280
|
+
try {
|
|
281
|
+
if (discrepancy.entityType === 'subscription') {
|
|
282
|
+
return this.fixSubscriptionDiscrepancy(discrepancy);
|
|
283
|
+
}
|
|
284
|
+
else if (discrepancy.entityType === 'invoice') {
|
|
285
|
+
return this.fixInvoiceDiscrepancy(discrepancy);
|
|
286
|
+
}
|
|
287
|
+
return false;
|
|
288
|
+
}
|
|
289
|
+
catch (error) {
|
|
290
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
291
|
+
logger.error('Failed to fix discrepancy', undefined, {
|
|
292
|
+
type: discrepancy.type,
|
|
293
|
+
entityId: discrepancy.entityId,
|
|
294
|
+
error: errorMsg,
|
|
295
|
+
});
|
|
296
|
+
return false;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
fixSubscriptionDiscrepancy(discrepancy) {
|
|
300
|
+
switch (discrepancy.type) {
|
|
301
|
+
case 'status_mismatch':
|
|
302
|
+
this.db
|
|
303
|
+
.prepare(`UPDATE user_subscriptions SET status = ?, updated_at = ? WHERE id = ?`)
|
|
304
|
+
.run(discrepancy.stripeValue, new Date().toISOString(), discrepancy.entityId);
|
|
305
|
+
logger.info('Fixed subscription status', {
|
|
306
|
+
entityId: discrepancy.entityId,
|
|
307
|
+
newStatus: discrepancy.stripeValue,
|
|
308
|
+
});
|
|
309
|
+
return true;
|
|
310
|
+
case 'tier_mismatch':
|
|
311
|
+
this.db
|
|
312
|
+
.prepare(`UPDATE user_subscriptions SET tier = ?, updated_at = ? WHERE id = ?`)
|
|
313
|
+
.run(discrepancy.stripeValue, new Date().toISOString(), discrepancy.entityId);
|
|
314
|
+
logger.info('Fixed subscription tier', {
|
|
315
|
+
entityId: discrepancy.entityId,
|
|
316
|
+
newTier: discrepancy.stripeValue,
|
|
317
|
+
});
|
|
318
|
+
return true;
|
|
319
|
+
case 'seat_count_mismatch':
|
|
320
|
+
this.db
|
|
321
|
+
.prepare(`UPDATE user_subscriptions SET seat_count = ?, updated_at = ? WHERE id = ?`)
|
|
322
|
+
.run(discrepancy.stripeValue, new Date().toISOString(), discrepancy.entityId);
|
|
323
|
+
logger.info('Fixed subscription seat count', {
|
|
324
|
+
entityId: discrepancy.entityId,
|
|
325
|
+
newSeatCount: discrepancy.stripeValue,
|
|
326
|
+
});
|
|
327
|
+
return true;
|
|
328
|
+
case 'missing_stripe':
|
|
329
|
+
// Mark local subscription as canceled if missing in Stripe
|
|
330
|
+
this.db
|
|
331
|
+
.prepare(`UPDATE user_subscriptions SET status = 'canceled', canceled_at = ?, updated_at = ? WHERE id = ?`)
|
|
332
|
+
.run(new Date().toISOString(), new Date().toISOString(), discrepancy.entityId);
|
|
333
|
+
logger.info('Marked missing subscription as canceled', { entityId: discrepancy.entityId });
|
|
334
|
+
return true;
|
|
335
|
+
default:
|
|
336
|
+
return false;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
fixInvoiceDiscrepancy(discrepancy) {
|
|
340
|
+
switch (discrepancy.type) {
|
|
341
|
+
case 'invoice_status_mismatch':
|
|
342
|
+
this.db
|
|
343
|
+
.prepare(`UPDATE invoices SET status = ? WHERE id = ?`)
|
|
344
|
+
.run(discrepancy.stripeValue, discrepancy.entityId);
|
|
345
|
+
logger.info('Fixed invoice status', {
|
|
346
|
+
entityId: discrepancy.entityId,
|
|
347
|
+
newStatus: discrepancy.stripeValue,
|
|
348
|
+
});
|
|
349
|
+
return true;
|
|
350
|
+
case 'invoice_amount_mismatch':
|
|
351
|
+
this.db
|
|
352
|
+
.prepare(`UPDATE invoices SET amount_cents = ? WHERE id = ?`)
|
|
353
|
+
.run(discrepancy.stripeValue, discrepancy.entityId);
|
|
354
|
+
logger.info('Fixed invoice amount', {
|
|
355
|
+
entityId: discrepancy.entityId,
|
|
356
|
+
newAmount: discrepancy.stripeValue,
|
|
357
|
+
});
|
|
358
|
+
return true;
|
|
359
|
+
default:
|
|
360
|
+
return false;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
// ============================================================================
|
|
365
|
+
// Helper Functions
|
|
366
|
+
// ============================================================================
|
|
367
|
+
function mapStripeStatus(stripeStatus) {
|
|
368
|
+
switch (stripeStatus) {
|
|
369
|
+
case 'active':
|
|
370
|
+
return 'active';
|
|
371
|
+
case 'past_due':
|
|
372
|
+
return 'past_due';
|
|
373
|
+
case 'canceled':
|
|
374
|
+
return 'canceled';
|
|
375
|
+
case 'trialing':
|
|
376
|
+
return 'trialing';
|
|
377
|
+
case 'paused':
|
|
378
|
+
return 'paused';
|
|
379
|
+
case 'incomplete':
|
|
380
|
+
return 'incomplete';
|
|
381
|
+
case 'incomplete_expired':
|
|
382
|
+
return 'incomplete_expired';
|
|
383
|
+
case 'unpaid':
|
|
384
|
+
return 'unpaid';
|
|
385
|
+
default:
|
|
386
|
+
return 'active';
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
function mapInvoiceStatus(stripeStatus) {
|
|
390
|
+
switch (stripeStatus) {
|
|
391
|
+
case 'paid':
|
|
392
|
+
return 'paid';
|
|
393
|
+
case 'open':
|
|
394
|
+
return 'open';
|
|
395
|
+
case 'draft':
|
|
396
|
+
return 'draft';
|
|
397
|
+
case 'void':
|
|
398
|
+
return 'void';
|
|
399
|
+
case 'uncollectible':
|
|
400
|
+
return 'uncollectible';
|
|
401
|
+
default:
|
|
402
|
+
return 'open';
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
//# sourceMappingURL=StripeReconciliationJob.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StripeReconciliationJob.js","sourceRoot":"","sources":["../../../src/billing/StripeReconciliationJob.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SMI-1070: Stripe Webhook Handler
|
|
3
|
+
*
|
|
4
|
+
* Processes Stripe webhook events for:
|
|
5
|
+
* - Subscription lifecycle (created, updated, deleted)
|
|
6
|
+
* - Invoice events (payment succeeded, payment failed)
|
|
7
|
+
* - Checkout session completion
|
|
8
|
+
*
|
|
9
|
+
* Features:
|
|
10
|
+
* - Idempotent event processing
|
|
11
|
+
* - Signature verification
|
|
12
|
+
* - License key generation on subscription creation
|
|
13
|
+
* - Status synchronization
|
|
14
|
+
*/
|
|
15
|
+
import type { Database as BetterSqliteDatabase } from 'better-sqlite3';
|
|
16
|
+
import { StripeClient } from './StripeClient.js';
|
|
17
|
+
import type { BillingService } from './BillingService.js';
|
|
18
|
+
import type { LicenseTier, WebhookProcessResult } from './types.js';
|
|
19
|
+
export interface StripeWebhookHandlerConfig {
|
|
20
|
+
/**
|
|
21
|
+
* StripeClient for API calls
|
|
22
|
+
*/
|
|
23
|
+
stripeClient: StripeClient;
|
|
24
|
+
/**
|
|
25
|
+
* BillingService for database operations
|
|
26
|
+
*/
|
|
27
|
+
billingService: BillingService;
|
|
28
|
+
/**
|
|
29
|
+
* Database connection (for license key storage)
|
|
30
|
+
*/
|
|
31
|
+
db: BetterSqliteDatabase;
|
|
32
|
+
/**
|
|
33
|
+
* Callback for license key generation
|
|
34
|
+
* Called when a subscription is created/activated
|
|
35
|
+
*/
|
|
36
|
+
onLicenseKeyNeeded?: (params: {
|
|
37
|
+
customerId: string;
|
|
38
|
+
tier: LicenseTier;
|
|
39
|
+
expiresAt: Date;
|
|
40
|
+
subscriptionId: string;
|
|
41
|
+
}) => Promise<string>;
|
|
42
|
+
/**
|
|
43
|
+
* Callback for sending emails
|
|
44
|
+
*/
|
|
45
|
+
onEmailNeeded?: (params: {
|
|
46
|
+
type: 'license_key' | 'payment_failed' | 'subscription_canceled';
|
|
47
|
+
email: string;
|
|
48
|
+
data: Record<string, unknown>;
|
|
49
|
+
}) => Promise<void>;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Handles Stripe webhook events
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```typescript
|
|
56
|
+
* const handler = new StripeWebhookHandler({
|
|
57
|
+
* stripeClient,
|
|
58
|
+
* billingService,
|
|
59
|
+
* db,
|
|
60
|
+
* onLicenseKeyNeeded: async (params) => {
|
|
61
|
+
* return licenseGenerator.createLicense(params);
|
|
62
|
+
* },
|
|
63
|
+
* });
|
|
64
|
+
*
|
|
65
|
+
* // In webhook endpoint:
|
|
66
|
+
* const result = await handler.handleWebhook(payload, signature);
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
export declare class StripeWebhookHandler {
|
|
70
|
+
private readonly stripe;
|
|
71
|
+
private readonly billing;
|
|
72
|
+
private readonly db;
|
|
73
|
+
private readonly onLicenseKeyNeeded?;
|
|
74
|
+
private readonly onEmailNeeded?;
|
|
75
|
+
constructor(config: StripeWebhookHandlerConfig);
|
|
76
|
+
/**
|
|
77
|
+
* Handle an incoming Stripe webhook
|
|
78
|
+
*/
|
|
79
|
+
handleWebhook(payload: string, signature: string): Promise<WebhookProcessResult>;
|
|
80
|
+
private routeEvent;
|
|
81
|
+
private handleSubscriptionCreated;
|
|
82
|
+
private handleSubscriptionUpdated;
|
|
83
|
+
private handleSubscriptionDeleted;
|
|
84
|
+
private handleInvoicePaymentSucceeded;
|
|
85
|
+
private handleInvoicePaymentFailed;
|
|
86
|
+
private handleCheckoutSessionCompleted;
|
|
87
|
+
private storeLicenseKey;
|
|
88
|
+
private revokeLicenseKey;
|
|
89
|
+
private extractTier;
|
|
90
|
+
private extractSeatCount;
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=StripeWebhookHandler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StripeWebhookHandler.d.ts","sourceRoot":"","sources":["../../../src/billing/StripeWebhookHandler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,OAAO,KAAK,EAAE,QAAQ,IAAI,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AAEtE,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAChD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AACzD,OAAO,KAAK,EACV,WAAW,EAIX,oBAAoB,EACrB,MAAM,YAAY,CAAA;AASnB,MAAM,WAAW,0BAA0B;IACzC;;OAEG;IACH,YAAY,EAAE,YAAY,CAAA;IAE1B;;OAEG;IACH,cAAc,EAAE,cAAc,CAAA;IAE9B;;OAEG;IACH,EAAE,EAAE,oBAAoB,CAAA;IAExB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,CAAC,MAAM,EAAE;QAC5B,UAAU,EAAE,MAAM,CAAA;QAClB,IAAI,EAAE,WAAW,CAAA;QACjB,SAAS,EAAE,IAAI,CAAA;QACf,cAAc,EAAE,MAAM,CAAA;KACvB,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;IAErB;;OAEG;IACH,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE;QACvB,IAAI,EAAE,aAAa,GAAG,gBAAgB,GAAG,uBAAuB,CAAA;QAChE,KAAK,EAAE,MAAM,CAAA;QACb,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAC9B,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CACpB;AAMD;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;IACrC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgB;IACxC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAsB;IACzC,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAkD;IACtF,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAA6C;gBAEhE,MAAM,EAAE,0BAA0B;IAc9C;;OAEG;IACG,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC;YAgFxE,UAAU;YAmCV,yBAAyB;YA6DzB,yBAAyB;YAoDzB,yBAAyB;YAyCzB,6BAA6B;YAgC7B,0BAA0B;YAgD1B,8BAA8B;IAe5C,OAAO,CAAC,eAAe;IAiCvB,OAAO,CAAC,gBAAgB;IAkBxB,OAAO,CAAC,WAAW;IAWnB,OAAO,CAAC,gBAAgB;CAazB"}
|