@hasna/microservices 0.0.15 → 0.0.17
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/README.md +120 -138
- package/bin/index.js +703 -12728
- package/bin/mcp.js +250 -9726
- package/dist/index.js +170 -9407
- package/package.json +25 -25
- package/microservices/microservice-ads/package.json +0 -27
- package/microservices/microservice-ads/src/cli/index.ts +0 -605
- package/microservices/microservice-ads/src/db/campaigns.ts +0 -797
- package/microservices/microservice-ads/src/db/database.ts +0 -93
- package/microservices/microservice-ads/src/db/migrations.ts +0 -60
- package/microservices/microservice-ads/src/index.ts +0 -39
- package/microservices/microservice-ads/src/mcp/index.ts +0 -480
- package/microservices/microservice-analytics/package.json +0 -27
- package/microservices/microservice-analytics/src/cli/index.ts +0 -373
- package/microservices/microservice-analytics/src/db/analytics.ts +0 -564
- package/microservices/microservice-analytics/src/db/database.ts +0 -93
- package/microservices/microservice-analytics/src/db/migrations.ts +0 -50
- package/microservices/microservice-analytics/src/index.ts +0 -37
- package/microservices/microservice-analytics/src/mcp/index.ts +0 -334
- package/microservices/microservice-assets/package.json +0 -27
- package/microservices/microservice-assets/src/cli/index.ts +0 -375
- package/microservices/microservice-assets/src/db/assets.ts +0 -370
- package/microservices/microservice-assets/src/db/database.ts +0 -93
- package/microservices/microservice-assets/src/db/migrations.ts +0 -51
- package/microservices/microservice-assets/src/index.ts +0 -32
- package/microservices/microservice-assets/src/mcp/index.ts +0 -346
- package/microservices/microservice-bookkeeping/package.json +0 -27
- package/microservices/microservice-bookkeeping/src/cli/index.ts +0 -386
- package/microservices/microservice-bookkeeping/src/db/bookkeeping.ts +0 -591
- package/microservices/microservice-bookkeeping/src/db/database.ts +0 -93
- package/microservices/microservice-bookkeeping/src/db/migrations.ts +0 -52
- package/microservices/microservice-bookkeeping/src/index.ts +0 -32
- package/microservices/microservice-bookkeeping/src/mcp/index.ts +0 -284
- package/microservices/microservice-calendar/package.json +0 -27
- package/microservices/microservice-calendar/src/cli/index.ts +0 -287
- package/microservices/microservice-calendar/src/db/calendar.ts +0 -328
- package/microservices/microservice-calendar/src/db/database.ts +0 -82
- package/microservices/microservice-calendar/src/db/migrations.ts +0 -47
- package/microservices/microservice-calendar/src/index.ts +0 -24
- package/microservices/microservice-calendar/src/mcp/index.ts +0 -226
- package/microservices/microservice-company/package.json +0 -27
- package/microservices/microservice-company/src/cli/index.ts +0 -1126
- package/microservices/microservice-company/src/db/company.ts +0 -854
- package/microservices/microservice-company/src/db/database.ts +0 -93
- package/microservices/microservice-company/src/db/migrations.ts +0 -214
- package/microservices/microservice-company/src/db/workflow-migrations.ts +0 -44
- package/microservices/microservice-company/src/index.ts +0 -60
- package/microservices/microservice-company/src/lib/audit.ts +0 -168
- package/microservices/microservice-company/src/lib/finance.ts +0 -299
- package/microservices/microservice-company/src/lib/settings.ts +0 -85
- package/microservices/microservice-company/src/lib/workflows.ts +0 -698
- package/microservices/microservice-company/src/mcp/index.ts +0 -991
- package/microservices/microservice-compliance/package.json +0 -27
- package/microservices/microservice-compliance/src/cli/index.ts +0 -467
- package/microservices/microservice-compliance/src/db/compliance.ts +0 -633
- package/microservices/microservice-compliance/src/db/database.ts +0 -93
- package/microservices/microservice-compliance/src/db/migrations.ts +0 -63
- package/microservices/microservice-compliance/src/index.ts +0 -46
- package/microservices/microservice-compliance/src/mcp/index.ts +0 -438
- package/microservices/microservice-contacts/package.json +0 -27
- package/microservices/microservice-contacts/src/cli/index.ts +0 -393
- package/microservices/microservice-contacts/src/db/companies.ts +0 -167
- package/microservices/microservice-contacts/src/db/contacts.ts +0 -249
- package/microservices/microservice-contacts/src/db/database.ts +0 -93
- package/microservices/microservice-contacts/src/db/migrations.ts +0 -71
- package/microservices/microservice-contacts/src/db/relationships.ts +0 -53
- package/microservices/microservice-contacts/src/index.ts +0 -42
- package/microservices/microservice-contacts/src/mcp/index.ts +0 -303
- package/microservices/microservice-contracts/package.json +0 -27
- package/microservices/microservice-contracts/src/cli/index.ts +0 -770
- package/microservices/microservice-contracts/src/db/contracts.ts +0 -925
- package/microservices/microservice-contracts/src/db/database.ts +0 -93
- package/microservices/microservice-contracts/src/db/migrations.ts +0 -141
- package/microservices/microservice-contracts/src/index.ts +0 -43
- package/microservices/microservice-contracts/src/mcp/index.ts +0 -617
- package/microservices/microservice-crm/package.json +0 -27
- package/microservices/microservice-crm/src/cli/index.ts +0 -396
- package/microservices/microservice-crm/src/db/database.ts +0 -82
- package/microservices/microservice-crm/src/db/migrations.ts +0 -66
- package/microservices/microservice-crm/src/db/pipeline.ts +0 -397
- package/microservices/microservice-crm/src/index.ts +0 -34
- package/microservices/microservice-crm/src/mcp/index.ts +0 -294
- package/microservices/microservice-documents/package.json +0 -27
- package/microservices/microservice-documents/src/cli/index.ts +0 -246
- package/microservices/microservice-documents/src/db/database.ts +0 -82
- package/microservices/microservice-documents/src/db/documents.ts +0 -316
- package/microservices/microservice-documents/src/db/migrations.ts +0 -49
- package/microservices/microservice-documents/src/index.ts +0 -24
- package/microservices/microservice-documents/src/mcp/index.ts +0 -202
- package/microservices/microservice-domains/package.json +0 -27
- package/microservices/microservice-domains/src/cli/index.ts +0 -1111
- package/microservices/microservice-domains/src/db/database.ts +0 -93
- package/microservices/microservice-domains/src/db/domains.ts +0 -1164
- package/microservices/microservice-domains/src/db/migrations.ts +0 -60
- package/microservices/microservice-domains/src/index.ts +0 -65
- package/microservices/microservice-domains/src/lib/brandsight.ts +0 -350
- package/microservices/microservice-domains/src/lib/godaddy.ts +0 -338
- package/microservices/microservice-domains/src/lib/namecheap.ts +0 -262
- package/microservices/microservice-domains/src/lib/registrar.ts +0 -355
- package/microservices/microservice-domains/src/mcp/index.ts +0 -781
- package/microservices/microservice-expenses/package.json +0 -27
- package/microservices/microservice-expenses/src/cli/index.ts +0 -267
- package/microservices/microservice-expenses/src/db/database.ts +0 -82
- package/microservices/microservice-expenses/src/db/expenses.ts +0 -345
- package/microservices/microservice-expenses/src/db/migrations.ts +0 -45
- package/microservices/microservice-expenses/src/index.ts +0 -25
- package/microservices/microservice-expenses/src/mcp/index.ts +0 -196
- package/microservices/microservice-habits/package.json +0 -27
- package/microservices/microservice-habits/src/cli/index.ts +0 -315
- package/microservices/microservice-habits/src/db/database.ts +0 -93
- package/microservices/microservice-habits/src/db/habits.ts +0 -451
- package/microservices/microservice-habits/src/db/migrations.ts +0 -46
- package/microservices/microservice-habits/src/index.ts +0 -31
- package/microservices/microservice-habits/src/mcp/index.ts +0 -313
- package/microservices/microservice-health/package.json +0 -27
- package/microservices/microservice-health/src/cli/index.ts +0 -484
- package/microservices/microservice-health/src/db/database.ts +0 -93
- package/microservices/microservice-health/src/db/health.ts +0 -708
- package/microservices/microservice-health/src/db/migrations.ts +0 -70
- package/microservices/microservice-health/src/index.ts +0 -63
- package/microservices/microservice-health/src/mcp/index.ts +0 -437
- package/microservices/microservice-hiring/package.json +0 -27
- package/microservices/microservice-hiring/src/cli/index.ts +0 -741
- package/microservices/microservice-hiring/src/db/database.ts +0 -93
- package/microservices/microservice-hiring/src/db/hiring.ts +0 -1085
- package/microservices/microservice-hiring/src/db/migrations.ts +0 -89
- package/microservices/microservice-hiring/src/index.ts +0 -80
- package/microservices/microservice-hiring/src/lib/scoring.ts +0 -206
- package/microservices/microservice-hiring/src/mcp/index.ts +0 -709
- package/microservices/microservice-inventory/package.json +0 -27
- package/microservices/microservice-inventory/src/cli/index.ts +0 -365
- package/microservices/microservice-inventory/src/db/database.ts +0 -82
- package/microservices/microservice-inventory/src/db/inventory.ts +0 -393
- package/microservices/microservice-inventory/src/db/migrations.ts +0 -54
- package/microservices/microservice-inventory/src/index.ts +0 -28
- package/microservices/microservice-inventory/src/mcp/index.ts +0 -250
- package/microservices/microservice-invoices/dashboard/dist/assets/index-Bngq7FNM.css +0 -1
- package/microservices/microservice-invoices/dashboard/dist/assets/index-aHW4ARZR.js +0 -124
- package/microservices/microservice-invoices/dashboard/dist/index.html +0 -13
- package/microservices/microservice-invoices/dashboard/index.html +0 -12
- package/microservices/microservice-invoices/dashboard/package.json +0 -29
- package/microservices/microservice-invoices/dashboard/tsconfig.json +0 -14
- package/microservices/microservice-invoices/dashboard/vite.config.ts +0 -15
- package/microservices/microservice-invoices/package.json +0 -30
- package/microservices/microservice-invoices/src/cli/index.ts +0 -308
- package/microservices/microservice-invoices/src/db/business.ts +0 -241
- package/microservices/microservice-invoices/src/db/clients.ts +0 -127
- package/microservices/microservice-invoices/src/db/database.ts +0 -82
- package/microservices/microservice-invoices/src/db/invoices.ts +0 -345
- package/microservices/microservice-invoices/src/db/migrations.ts +0 -184
- package/microservices/microservice-invoices/src/index.ts +0 -56
- package/microservices/microservice-invoices/src/mcp/index.ts +0 -242
- package/microservices/microservice-invoices/src/server/index.ts +0 -162
- package/microservices/microservice-leads/package.json +0 -27
- package/microservices/microservice-leads/src/cli/index.ts +0 -596
- package/microservices/microservice-leads/src/db/database.ts +0 -93
- package/microservices/microservice-leads/src/db/leads.ts +0 -520
- package/microservices/microservice-leads/src/db/lists.ts +0 -151
- package/microservices/microservice-leads/src/db/migrations.ts +0 -93
- package/microservices/microservice-leads/src/index.ts +0 -65
- package/microservices/microservice-leads/src/lib/enrichment.ts +0 -202
- package/microservices/microservice-leads/src/lib/scoring.ts +0 -134
- package/microservices/microservice-leads/src/mcp/index.ts +0 -533
- package/microservices/microservice-notes/package.json +0 -27
- package/microservices/microservice-notes/src/cli/index.ts +0 -63
- package/microservices/microservice-notes/src/db/database.ts +0 -93
- package/microservices/microservice-notes/src/db/migrations.ts +0 -40
- package/microservices/microservice-notes/src/db/notes.ts +0 -114
- package/microservices/microservice-notes/src/index.ts +0 -2
- package/microservices/microservice-notes/src/mcp/index.ts +0 -37
- package/microservices/microservice-notifications/package.json +0 -27
- package/microservices/microservice-notifications/src/cli/index.ts +0 -349
- package/microservices/microservice-notifications/src/db/database.ts +0 -93
- package/microservices/microservice-notifications/src/db/migrations.ts +0 -62
- package/microservices/microservice-notifications/src/db/notifications.ts +0 -509
- package/microservices/microservice-notifications/src/index.ts +0 -41
- package/microservices/microservice-notifications/src/mcp/index.ts +0 -422
- package/microservices/microservice-payments/package.json +0 -27
- package/microservices/microservice-payments/src/cli/index.ts +0 -609
- package/microservices/microservice-payments/src/db/database.ts +0 -93
- package/microservices/microservice-payments/src/db/migrations.ts +0 -81
- package/microservices/microservice-payments/src/db/payments.ts +0 -1204
- package/microservices/microservice-payments/src/index.ts +0 -51
- package/microservices/microservice-payments/src/mcp/index.ts +0 -683
- package/microservices/microservice-payroll/package.json +0 -27
- package/microservices/microservice-payroll/src/cli/index.ts +0 -643
- package/microservices/microservice-payroll/src/db/database.ts +0 -93
- package/microservices/microservice-payroll/src/db/migrations.ts +0 -95
- package/microservices/microservice-payroll/src/db/payroll.ts +0 -1377
- package/microservices/microservice-payroll/src/index.ts +0 -48
- package/microservices/microservice-payroll/src/mcp/index.ts +0 -666
- package/microservices/microservice-products/package.json +0 -27
- package/microservices/microservice-products/src/cli/index.ts +0 -416
- package/microservices/microservice-products/src/db/categories.ts +0 -154
- package/microservices/microservice-products/src/db/database.ts +0 -93
- package/microservices/microservice-products/src/db/migrations.ts +0 -58
- package/microservices/microservice-products/src/db/pricing-tiers.ts +0 -66
- package/microservices/microservice-products/src/db/products.ts +0 -452
- package/microservices/microservice-products/src/index.ts +0 -53
- package/microservices/microservice-products/src/mcp/index.ts +0 -453
- package/microservices/microservice-projects/package.json +0 -27
- package/microservices/microservice-projects/src/cli/index.ts +0 -480
- package/microservices/microservice-projects/src/db/database.ts +0 -93
- package/microservices/microservice-projects/src/db/migrations.ts +0 -65
- package/microservices/microservice-projects/src/db/projects.ts +0 -715
- package/microservices/microservice-projects/src/index.ts +0 -57
- package/microservices/microservice-projects/src/mcp/index.ts +0 -501
- package/microservices/microservice-proposals/package.json +0 -27
- package/microservices/microservice-proposals/src/cli/index.ts +0 -400
- package/microservices/microservice-proposals/src/db/database.ts +0 -93
- package/microservices/microservice-proposals/src/db/migrations.ts +0 -52
- package/microservices/microservice-proposals/src/db/proposals.ts +0 -532
- package/microservices/microservice-proposals/src/index.ts +0 -37
- package/microservices/microservice-proposals/src/mcp/index.ts +0 -375
- package/microservices/microservice-reading/package.json +0 -27
- package/microservices/microservice-reading/src/cli/index.ts +0 -464
- package/microservices/microservice-reading/src/db/database.ts +0 -93
- package/microservices/microservice-reading/src/db/migrations.ts +0 -59
- package/microservices/microservice-reading/src/db/reading.ts +0 -524
- package/microservices/microservice-reading/src/index.ts +0 -51
- package/microservices/microservice-reading/src/mcp/index.ts +0 -368
- package/microservices/microservice-shipping/package.json +0 -27
- package/microservices/microservice-shipping/src/cli/index.ts +0 -606
- package/microservices/microservice-shipping/src/db/database.ts +0 -93
- package/microservices/microservice-shipping/src/db/migrations.ts +0 -69
- package/microservices/microservice-shipping/src/db/shipping.ts +0 -1093
- package/microservices/microservice-shipping/src/index.ts +0 -53
- package/microservices/microservice-shipping/src/mcp/index.ts +0 -533
- package/microservices/microservice-social/package.json +0 -28
- package/microservices/microservice-social/src/cli/index.ts +0 -1583
- package/microservices/microservice-social/src/db/database.ts +0 -93
- package/microservices/microservice-social/src/db/migrations.ts +0 -160
- package/microservices/microservice-social/src/db/social.ts +0 -1076
- package/microservices/microservice-social/src/index.ts +0 -46
- package/microservices/microservice-social/src/lib/audience.ts +0 -353
- package/microservices/microservice-social/src/lib/content-ai.ts +0 -278
- package/microservices/microservice-social/src/lib/media.ts +0 -311
- package/microservices/microservice-social/src/lib/mentions.ts +0 -434
- package/microservices/microservice-social/src/lib/metrics-sync.ts +0 -264
- package/microservices/microservice-social/src/lib/publisher.ts +0 -377
- package/microservices/microservice-social/src/lib/scheduler.ts +0 -229
- package/microservices/microservice-social/src/lib/sentiment.ts +0 -256
- package/microservices/microservice-social/src/lib/threads.ts +0 -291
- package/microservices/microservice-social/src/mcp/index.ts +0 -1425
- package/microservices/microservice-social/src/server/index.ts +0 -441
- package/microservices/microservice-subscriptions/package.json +0 -27
- package/microservices/microservice-subscriptions/src/cli/index.ts +0 -715
- package/microservices/microservice-subscriptions/src/db/database.ts +0 -93
- package/microservices/microservice-subscriptions/src/db/migrations.ts +0 -125
- package/microservices/microservice-subscriptions/src/db/subscriptions.ts +0 -1256
- package/microservices/microservice-subscriptions/src/index.ts +0 -41
- package/microservices/microservice-subscriptions/src/mcp/index.ts +0 -631
- package/microservices/microservice-timesheets/package.json +0 -27
- package/microservices/microservice-timesheets/src/cli/index.ts +0 -373
- package/microservices/microservice-timesheets/src/db/database.ts +0 -82
- package/microservices/microservice-timesheets/src/db/locale.ts +0 -217
- package/microservices/microservice-timesheets/src/db/migrations.ts +0 -74
- package/microservices/microservice-timesheets/src/db/timesheets.ts +0 -447
- package/microservices/microservice-timesheets/src/index.ts +0 -44
- package/microservices/microservice-timesheets/src/mcp/index.ts +0 -269
- package/microservices/microservice-transcriber/package.json +0 -28
- package/microservices/microservice-transcriber/src/cli/index.ts +0 -1593
- package/microservices/microservice-transcriber/src/db/annotations.ts +0 -37
- package/microservices/microservice-transcriber/src/db/comments.ts +0 -166
- package/microservices/microservice-transcriber/src/db/database.ts +0 -82
- package/microservices/microservice-transcriber/src/db/migrations.ts +0 -118
- package/microservices/microservice-transcriber/src/db/proofread.ts +0 -119
- package/microservices/microservice-transcriber/src/db/transcripts.ts +0 -395
- package/microservices/microservice-transcriber/src/index.ts +0 -43
- package/microservices/microservice-transcriber/src/lib/config.ts +0 -77
- package/microservices/microservice-transcriber/src/lib/diff.ts +0 -91
- package/microservices/microservice-transcriber/src/lib/downloader.ts +0 -638
- package/microservices/microservice-transcriber/src/lib/feeds.ts +0 -62
- package/microservices/microservice-transcriber/src/lib/live.ts +0 -94
- package/microservices/microservice-transcriber/src/lib/notion.ts +0 -129
- package/microservices/microservice-transcriber/src/lib/proofread.ts +0 -296
- package/microservices/microservice-transcriber/src/lib/providers.ts +0 -713
- package/microservices/microservice-transcriber/src/lib/summarizer.ts +0 -147
- package/microservices/microservice-transcriber/src/lib/translator.ts +0 -75
- package/microservices/microservice-transcriber/src/lib/webhook.ts +0 -37
- package/microservices/microservice-transcriber/src/mcp/index.ts +0 -1330
- package/microservices/microservice-transcriber/src/server/index.ts +0 -199
- package/microservices/microservice-travel/package.json +0 -27
- package/microservices/microservice-travel/src/cli/index.ts +0 -505
- package/microservices/microservice-travel/src/db/database.ts +0 -93
- package/microservices/microservice-travel/src/db/migrations.ts +0 -77
- package/microservices/microservice-travel/src/db/travel.ts +0 -802
- package/microservices/microservice-travel/src/index.ts +0 -60
- package/microservices/microservice-travel/src/mcp/index.ts +0 -495
- package/microservices/microservice-wiki/package.json +0 -27
- package/microservices/microservice-wiki/src/cli/index.ts +0 -345
- package/microservices/microservice-wiki/src/db/database.ts +0 -93
- package/microservices/microservice-wiki/src/db/migrations.ts +0 -55
- package/microservices/microservice-wiki/src/db/wiki.ts +0 -395
- package/microservices/microservice-wiki/src/index.ts +0 -32
- package/microservices/microservice-wiki/src/mcp/index.ts +0 -344
|
@@ -1,591 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Bookkeeping CRUD operations — double-entry accounting
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { getDatabase } from "./database.js";
|
|
6
|
-
|
|
7
|
-
// --- Types ---
|
|
8
|
-
|
|
9
|
-
export type AccountType = "asset" | "liability" | "equity" | "revenue" | "expense";
|
|
10
|
-
|
|
11
|
-
export interface Account {
|
|
12
|
-
id: string;
|
|
13
|
-
name: string;
|
|
14
|
-
type: AccountType;
|
|
15
|
-
code: string | null;
|
|
16
|
-
description: string | null;
|
|
17
|
-
parent_id: string | null;
|
|
18
|
-
balance: number;
|
|
19
|
-
currency: string;
|
|
20
|
-
created_at: string;
|
|
21
|
-
updated_at: string;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export interface Transaction {
|
|
25
|
-
id: string;
|
|
26
|
-
date: string;
|
|
27
|
-
description: string;
|
|
28
|
-
reference: string | null;
|
|
29
|
-
metadata: Record<string, unknown>;
|
|
30
|
-
created_at: string;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
interface TransactionRow {
|
|
34
|
-
id: string;
|
|
35
|
-
date: string;
|
|
36
|
-
description: string;
|
|
37
|
-
reference: string | null;
|
|
38
|
-
metadata: string;
|
|
39
|
-
created_at: string;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export interface TransactionEntry {
|
|
43
|
-
id: string;
|
|
44
|
-
transaction_id: string;
|
|
45
|
-
account_id: string;
|
|
46
|
-
debit: number;
|
|
47
|
-
credit: number;
|
|
48
|
-
description: string | null;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export interface TransactionWithEntries extends Transaction {
|
|
52
|
-
entries: TransactionEntry[];
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function rowToTransaction(row: TransactionRow): Transaction {
|
|
56
|
-
return {
|
|
57
|
-
...row,
|
|
58
|
-
metadata: JSON.parse(row.metadata || "{}"),
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// --- Accounts ---
|
|
63
|
-
|
|
64
|
-
export interface CreateAccountInput {
|
|
65
|
-
name: string;
|
|
66
|
-
type: AccountType;
|
|
67
|
-
code?: string;
|
|
68
|
-
description?: string;
|
|
69
|
-
parent_id?: string;
|
|
70
|
-
currency?: string;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export function createAccount(input: CreateAccountInput): Account {
|
|
74
|
-
const db = getDatabase();
|
|
75
|
-
const id = crypto.randomUUID();
|
|
76
|
-
|
|
77
|
-
db.prepare(
|
|
78
|
-
`INSERT INTO accounts (id, name, type, code, description, parent_id, currency)
|
|
79
|
-
VALUES (?, ?, ?, ?, ?, ?, ?)`
|
|
80
|
-
).run(
|
|
81
|
-
id,
|
|
82
|
-
input.name,
|
|
83
|
-
input.type,
|
|
84
|
-
input.code || null,
|
|
85
|
-
input.description || null,
|
|
86
|
-
input.parent_id || null,
|
|
87
|
-
input.currency || "USD"
|
|
88
|
-
);
|
|
89
|
-
|
|
90
|
-
return getAccount(id)!;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
export function getAccount(id: string): Account | null {
|
|
94
|
-
const db = getDatabase();
|
|
95
|
-
const row = db.prepare("SELECT * FROM accounts WHERE id = ? OR code = ?").get(id, id) as Account | null;
|
|
96
|
-
return row || null;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
export interface ListAccountsOptions {
|
|
100
|
-
type?: AccountType;
|
|
101
|
-
parent_id?: string;
|
|
102
|
-
currency?: string;
|
|
103
|
-
search?: string;
|
|
104
|
-
limit?: number;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
export function listAccounts(options: ListAccountsOptions = {}): Account[] {
|
|
108
|
-
const db = getDatabase();
|
|
109
|
-
const conditions: string[] = [];
|
|
110
|
-
const params: unknown[] = [];
|
|
111
|
-
|
|
112
|
-
if (options.type) {
|
|
113
|
-
conditions.push("type = ?");
|
|
114
|
-
params.push(options.type);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
if (options.parent_id) {
|
|
118
|
-
conditions.push("parent_id = ?");
|
|
119
|
-
params.push(options.parent_id);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
if (options.currency) {
|
|
123
|
-
conditions.push("currency = ?");
|
|
124
|
-
params.push(options.currency);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
if (options.search) {
|
|
128
|
-
conditions.push("(name LIKE ? OR code LIKE ? OR description LIKE ?)");
|
|
129
|
-
const q = `%${options.search}%`;
|
|
130
|
-
params.push(q, q, q);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
let sql = "SELECT * FROM accounts";
|
|
134
|
-
if (conditions.length > 0) {
|
|
135
|
-
sql += " WHERE " + conditions.join(" AND ");
|
|
136
|
-
}
|
|
137
|
-
sql += " ORDER BY type, code, name";
|
|
138
|
-
|
|
139
|
-
if (options.limit) {
|
|
140
|
-
sql += " LIMIT ?";
|
|
141
|
-
params.push(options.limit);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
return db.prepare(sql).all(...params) as Account[];
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
export interface UpdateAccountInput {
|
|
148
|
-
name?: string;
|
|
149
|
-
type?: AccountType;
|
|
150
|
-
code?: string;
|
|
151
|
-
description?: string;
|
|
152
|
-
parent_id?: string | null;
|
|
153
|
-
currency?: string;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
export function updateAccount(id: string, input: UpdateAccountInput): Account | null {
|
|
157
|
-
const db = getDatabase();
|
|
158
|
-
const existing = getAccount(id);
|
|
159
|
-
if (!existing) return null;
|
|
160
|
-
|
|
161
|
-
const sets: string[] = [];
|
|
162
|
-
const params: unknown[] = [];
|
|
163
|
-
|
|
164
|
-
if (input.name !== undefined) {
|
|
165
|
-
sets.push("name = ?");
|
|
166
|
-
params.push(input.name);
|
|
167
|
-
}
|
|
168
|
-
if (input.type !== undefined) {
|
|
169
|
-
sets.push("type = ?");
|
|
170
|
-
params.push(input.type);
|
|
171
|
-
}
|
|
172
|
-
if (input.code !== undefined) {
|
|
173
|
-
sets.push("code = ?");
|
|
174
|
-
params.push(input.code);
|
|
175
|
-
}
|
|
176
|
-
if (input.description !== undefined) {
|
|
177
|
-
sets.push("description = ?");
|
|
178
|
-
params.push(input.description);
|
|
179
|
-
}
|
|
180
|
-
if (input.parent_id !== undefined) {
|
|
181
|
-
sets.push("parent_id = ?");
|
|
182
|
-
params.push(input.parent_id);
|
|
183
|
-
}
|
|
184
|
-
if (input.currency !== undefined) {
|
|
185
|
-
sets.push("currency = ?");
|
|
186
|
-
params.push(input.currency);
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
if (sets.length === 0) return existing;
|
|
190
|
-
|
|
191
|
-
sets.push("updated_at = datetime('now')");
|
|
192
|
-
params.push(existing.id);
|
|
193
|
-
|
|
194
|
-
db.prepare(
|
|
195
|
-
`UPDATE accounts SET ${sets.join(", ")} WHERE id = ?`
|
|
196
|
-
).run(...params);
|
|
197
|
-
|
|
198
|
-
return getAccount(existing.id);
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
export function deleteAccount(id: string): boolean {
|
|
202
|
-
const db = getDatabase();
|
|
203
|
-
// Check if account has transaction entries
|
|
204
|
-
const hasEntries = db
|
|
205
|
-
.prepare("SELECT COUNT(*) as count FROM transaction_entries WHERE account_id = ?")
|
|
206
|
-
.get(id) as { count: number };
|
|
207
|
-
|
|
208
|
-
if (hasEntries.count > 0) {
|
|
209
|
-
throw new Error("Cannot delete account with existing transaction entries");
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
return db.prepare("DELETE FROM accounts WHERE id = ?").run(id).changes > 0;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// --- Transactions ---
|
|
216
|
-
|
|
217
|
-
export interface TransactionEntryInput {
|
|
218
|
-
account_id: string;
|
|
219
|
-
debit?: number;
|
|
220
|
-
credit?: number;
|
|
221
|
-
description?: string;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
export interface CreateTransactionInput {
|
|
225
|
-
date?: string;
|
|
226
|
-
description: string;
|
|
227
|
-
reference?: string;
|
|
228
|
-
metadata?: Record<string, unknown>;
|
|
229
|
-
entries: TransactionEntryInput[];
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
export function createTransaction(input: CreateTransactionInput): TransactionWithEntries {
|
|
233
|
-
const db = getDatabase();
|
|
234
|
-
|
|
235
|
-
if (input.entries.length < 2) {
|
|
236
|
-
throw new Error("Transaction must have at least two entries");
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
// Validate double-entry: total debits must equal total credits
|
|
240
|
-
let totalDebits = 0;
|
|
241
|
-
let totalCredits = 0;
|
|
242
|
-
for (const entry of input.entries) {
|
|
243
|
-
totalDebits += entry.debit || 0;
|
|
244
|
-
totalCredits += entry.credit || 0;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
// Round to avoid floating point issues
|
|
248
|
-
totalDebits = Math.round(totalDebits * 100) / 100;
|
|
249
|
-
totalCredits = Math.round(totalCredits * 100) / 100;
|
|
250
|
-
|
|
251
|
-
if (totalDebits === 0) {
|
|
252
|
-
throw new Error("Transaction must have at least one debit and one credit entry");
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
if (totalDebits !== totalCredits) {
|
|
256
|
-
throw new Error(
|
|
257
|
-
`Transaction does not balance: debits (${totalDebits}) != credits (${totalCredits})`
|
|
258
|
-
);
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
const id = crypto.randomUUID();
|
|
262
|
-
const metadata = JSON.stringify(input.metadata || {});
|
|
263
|
-
|
|
264
|
-
db.exec("BEGIN");
|
|
265
|
-
try {
|
|
266
|
-
db.prepare(
|
|
267
|
-
`INSERT INTO transactions (id, date, description, reference, metadata)
|
|
268
|
-
VALUES (?, ?, ?, ?, ?)`
|
|
269
|
-
).run(
|
|
270
|
-
id,
|
|
271
|
-
input.date || new Date().toISOString().split("T")[0],
|
|
272
|
-
input.description,
|
|
273
|
-
input.reference || null,
|
|
274
|
-
metadata
|
|
275
|
-
);
|
|
276
|
-
|
|
277
|
-
const insertEntry = db.prepare(
|
|
278
|
-
`INSERT INTO transaction_entries (id, transaction_id, account_id, debit, credit, description)
|
|
279
|
-
VALUES (?, ?, ?, ?, ?, ?)`
|
|
280
|
-
);
|
|
281
|
-
|
|
282
|
-
for (const entry of input.entries) {
|
|
283
|
-
insertEntry.run(
|
|
284
|
-
crypto.randomUUID(),
|
|
285
|
-
id,
|
|
286
|
-
entry.account_id,
|
|
287
|
-
entry.debit || 0,
|
|
288
|
-
entry.credit || 0,
|
|
289
|
-
entry.description || null
|
|
290
|
-
);
|
|
291
|
-
|
|
292
|
-
// Update account balance
|
|
293
|
-
// Asset/Expense: debit increases, credit decreases
|
|
294
|
-
// Liability/Equity/Revenue: credit increases, debit decreases
|
|
295
|
-
const debit = entry.debit || 0;
|
|
296
|
-
const credit = entry.credit || 0;
|
|
297
|
-
const account = db.prepare("SELECT type FROM accounts WHERE id = ?").get(entry.account_id) as { type: AccountType } | null;
|
|
298
|
-
|
|
299
|
-
if (!account) {
|
|
300
|
-
throw new Error(`Account '${entry.account_id}' not found`);
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
let balanceChange: number;
|
|
304
|
-
if (account.type === "asset" || account.type === "expense") {
|
|
305
|
-
balanceChange = debit - credit;
|
|
306
|
-
} else {
|
|
307
|
-
balanceChange = credit - debit;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
db.prepare(
|
|
311
|
-
"UPDATE accounts SET balance = balance + ?, updated_at = datetime('now') WHERE id = ?"
|
|
312
|
-
).run(balanceChange, entry.account_id);
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
db.exec("COMMIT");
|
|
316
|
-
} catch (error) {
|
|
317
|
-
db.exec("ROLLBACK");
|
|
318
|
-
throw error;
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
return getTransaction(id)!;
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
export function getTransaction(id: string): TransactionWithEntries | null {
|
|
325
|
-
const db = getDatabase();
|
|
326
|
-
const row = db.prepare("SELECT * FROM transactions WHERE id = ? OR reference = ?").get(id, id) as TransactionRow | null;
|
|
327
|
-
if (!row) return null;
|
|
328
|
-
|
|
329
|
-
const transaction = rowToTransaction(row);
|
|
330
|
-
const entries = db
|
|
331
|
-
.prepare("SELECT * FROM transaction_entries WHERE transaction_id = ? ORDER BY debit DESC")
|
|
332
|
-
.all(transaction.id) as TransactionEntry[];
|
|
333
|
-
|
|
334
|
-
return { ...transaction, entries };
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
export interface ListTransactionsOptions {
|
|
338
|
-
from_date?: string;
|
|
339
|
-
to_date?: string;
|
|
340
|
-
account_id?: string;
|
|
341
|
-
reference?: string;
|
|
342
|
-
search?: string;
|
|
343
|
-
limit?: number;
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
export function listTransactions(options: ListTransactionsOptions = {}): TransactionWithEntries[] {
|
|
347
|
-
const db = getDatabase();
|
|
348
|
-
const conditions: string[] = [];
|
|
349
|
-
const params: unknown[] = [];
|
|
350
|
-
|
|
351
|
-
if (options.from_date) {
|
|
352
|
-
conditions.push("t.date >= ?");
|
|
353
|
-
params.push(options.from_date);
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
if (options.to_date) {
|
|
357
|
-
conditions.push("t.date <= ?");
|
|
358
|
-
params.push(options.to_date);
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
if (options.account_id) {
|
|
362
|
-
conditions.push(
|
|
363
|
-
"t.id IN (SELECT transaction_id FROM transaction_entries WHERE account_id = ?)"
|
|
364
|
-
);
|
|
365
|
-
params.push(options.account_id);
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
if (options.reference) {
|
|
369
|
-
conditions.push("t.reference = ?");
|
|
370
|
-
params.push(options.reference);
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
if (options.search) {
|
|
374
|
-
conditions.push("(t.description LIKE ? OR t.reference LIKE ?)");
|
|
375
|
-
const q = `%${options.search}%`;
|
|
376
|
-
params.push(q, q);
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
let sql = "SELECT t.* FROM transactions t";
|
|
380
|
-
if (conditions.length > 0) {
|
|
381
|
-
sql += " WHERE " + conditions.join(" AND ");
|
|
382
|
-
}
|
|
383
|
-
sql += " ORDER BY t.date DESC, t.created_at DESC";
|
|
384
|
-
|
|
385
|
-
if (options.limit) {
|
|
386
|
-
sql += " LIMIT ?";
|
|
387
|
-
params.push(options.limit);
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
const rows = db.prepare(sql).all(...params) as TransactionRow[];
|
|
391
|
-
|
|
392
|
-
return rows.map((row) => {
|
|
393
|
-
const transaction = rowToTransaction(row);
|
|
394
|
-
const entries = db
|
|
395
|
-
.prepare("SELECT * FROM transaction_entries WHERE transaction_id = ? ORDER BY debit DESC")
|
|
396
|
-
.all(transaction.id) as TransactionEntry[];
|
|
397
|
-
return { ...transaction, entries };
|
|
398
|
-
});
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
export function deleteTransaction(id: string): boolean {
|
|
402
|
-
const db = getDatabase();
|
|
403
|
-
|
|
404
|
-
// Get the transaction with entries to reverse balances
|
|
405
|
-
const txn = getTransaction(id);
|
|
406
|
-
if (!txn) return false;
|
|
407
|
-
|
|
408
|
-
db.exec("BEGIN");
|
|
409
|
-
try {
|
|
410
|
-
// Reverse account balances
|
|
411
|
-
for (const entry of txn.entries) {
|
|
412
|
-
const account = db.prepare("SELECT type FROM accounts WHERE id = ?").get(entry.account_id) as { type: AccountType } | null;
|
|
413
|
-
if (!account) continue;
|
|
414
|
-
|
|
415
|
-
let balanceChange: number;
|
|
416
|
-
if (account.type === "asset" || account.type === "expense") {
|
|
417
|
-
balanceChange = entry.credit - entry.debit; // reverse
|
|
418
|
-
} else {
|
|
419
|
-
balanceChange = entry.debit - entry.credit; // reverse
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
db.prepare(
|
|
423
|
-
"UPDATE accounts SET balance = balance + ?, updated_at = datetime('now') WHERE id = ?"
|
|
424
|
-
).run(balanceChange, entry.account_id);
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
db.prepare("DELETE FROM transactions WHERE id = ?").run(txn.id);
|
|
428
|
-
db.exec("COMMIT");
|
|
429
|
-
} catch (error) {
|
|
430
|
-
db.exec("ROLLBACK");
|
|
431
|
-
throw error;
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
return true;
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
// --- Reports ---
|
|
438
|
-
|
|
439
|
-
export interface TrialBalanceEntry {
|
|
440
|
-
account_id: string;
|
|
441
|
-
account_name: string;
|
|
442
|
-
account_type: AccountType;
|
|
443
|
-
account_code: string | null;
|
|
444
|
-
debit: number;
|
|
445
|
-
credit: number;
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
export function getTrialBalance(): {
|
|
449
|
-
entries: TrialBalanceEntry[];
|
|
450
|
-
total_debits: number;
|
|
451
|
-
total_credits: number;
|
|
452
|
-
balanced: boolean;
|
|
453
|
-
} {
|
|
454
|
-
const db = getDatabase();
|
|
455
|
-
|
|
456
|
-
const rows = db
|
|
457
|
-
.prepare(
|
|
458
|
-
`SELECT
|
|
459
|
-
a.id as account_id,
|
|
460
|
-
a.name as account_name,
|
|
461
|
-
a.type as account_type,
|
|
462
|
-
a.code as account_code,
|
|
463
|
-
COALESCE(SUM(te.debit), 0) as debit,
|
|
464
|
-
COALESCE(SUM(te.credit), 0) as credit
|
|
465
|
-
FROM accounts a
|
|
466
|
-
LEFT JOIN transaction_entries te ON a.id = te.account_id
|
|
467
|
-
GROUP BY a.id
|
|
468
|
-
HAVING debit > 0 OR credit > 0
|
|
469
|
-
ORDER BY a.type, a.code, a.name`
|
|
470
|
-
)
|
|
471
|
-
.all() as TrialBalanceEntry[];
|
|
472
|
-
|
|
473
|
-
let totalDebits = 0;
|
|
474
|
-
let totalCredits = 0;
|
|
475
|
-
for (const row of rows) {
|
|
476
|
-
totalDebits += row.debit;
|
|
477
|
-
totalCredits += row.credit;
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
totalDebits = Math.round(totalDebits * 100) / 100;
|
|
481
|
-
totalCredits = Math.round(totalCredits * 100) / 100;
|
|
482
|
-
|
|
483
|
-
return {
|
|
484
|
-
entries: rows,
|
|
485
|
-
total_debits: totalDebits,
|
|
486
|
-
total_credits: totalCredits,
|
|
487
|
-
balanced: totalDebits === totalCredits,
|
|
488
|
-
};
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
export function getAccountBalance(accountId: string): {
|
|
492
|
-
account: Account;
|
|
493
|
-
total_debits: number;
|
|
494
|
-
total_credits: number;
|
|
495
|
-
balance: number;
|
|
496
|
-
} | null {
|
|
497
|
-
const account = getAccount(accountId);
|
|
498
|
-
if (!account) return null;
|
|
499
|
-
|
|
500
|
-
const db = getDatabase();
|
|
501
|
-
const row = db
|
|
502
|
-
.prepare(
|
|
503
|
-
`SELECT
|
|
504
|
-
COALESCE(SUM(debit), 0) as total_debits,
|
|
505
|
-
COALESCE(SUM(credit), 0) as total_credits
|
|
506
|
-
FROM transaction_entries
|
|
507
|
-
WHERE account_id = ?`
|
|
508
|
-
)
|
|
509
|
-
.get(account.id) as { total_debits: number; total_credits: number };
|
|
510
|
-
|
|
511
|
-
return {
|
|
512
|
-
account,
|
|
513
|
-
total_debits: row.total_debits,
|
|
514
|
-
total_credits: row.total_credits,
|
|
515
|
-
balance: account.balance,
|
|
516
|
-
};
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
export function getIncomeStatement(options: {
|
|
520
|
-
from_date?: string;
|
|
521
|
-
to_date?: string;
|
|
522
|
-
} = {}): {
|
|
523
|
-
revenue: { account_id: string; account_name: string; account_code: string | null; amount: number }[];
|
|
524
|
-
expenses: { account_id: string; account_name: string; account_code: string | null; amount: number }[];
|
|
525
|
-
total_revenue: number;
|
|
526
|
-
total_expenses: number;
|
|
527
|
-
net_income: number;
|
|
528
|
-
} {
|
|
529
|
-
const db = getDatabase();
|
|
530
|
-
const conditions: string[] = [];
|
|
531
|
-
const params: unknown[] = [];
|
|
532
|
-
|
|
533
|
-
if (options.from_date) {
|
|
534
|
-
conditions.push("t.date >= ?");
|
|
535
|
-
params.push(options.from_date);
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
if (options.to_date) {
|
|
539
|
-
conditions.push("t.date <= ?");
|
|
540
|
-
params.push(options.to_date);
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
const dateFilter = conditions.length > 0 ? " AND " + conditions.join(" AND ") : "";
|
|
544
|
-
|
|
545
|
-
// Revenue: credit increases balance
|
|
546
|
-
const revenueRows = db
|
|
547
|
-
.prepare(
|
|
548
|
-
`SELECT
|
|
549
|
-
a.id as account_id,
|
|
550
|
-
a.name as account_name,
|
|
551
|
-
a.code as account_code,
|
|
552
|
-
COALESCE(SUM(te.credit) - SUM(te.debit), 0) as amount
|
|
553
|
-
FROM accounts a
|
|
554
|
-
LEFT JOIN transaction_entries te ON a.id = te.account_id
|
|
555
|
-
LEFT JOIN transactions t ON te.transaction_id = t.id
|
|
556
|
-
WHERE a.type = 'revenue'${dateFilter}
|
|
557
|
-
GROUP BY a.id
|
|
558
|
-
HAVING amount != 0
|
|
559
|
-
ORDER BY a.code, a.name`
|
|
560
|
-
)
|
|
561
|
-
.all(...params) as { account_id: string; account_name: string; account_code: string | null; amount: number }[];
|
|
562
|
-
|
|
563
|
-
// Expenses: debit increases balance
|
|
564
|
-
const expenseRows = db
|
|
565
|
-
.prepare(
|
|
566
|
-
`SELECT
|
|
567
|
-
a.id as account_id,
|
|
568
|
-
a.name as account_name,
|
|
569
|
-
a.code as account_code,
|
|
570
|
-
COALESCE(SUM(te.debit) - SUM(te.credit), 0) as amount
|
|
571
|
-
FROM accounts a
|
|
572
|
-
LEFT JOIN transaction_entries te ON a.id = te.account_id
|
|
573
|
-
LEFT JOIN transactions t ON te.transaction_id = t.id
|
|
574
|
-
WHERE a.type = 'expense'${dateFilter}
|
|
575
|
-
GROUP BY a.id
|
|
576
|
-
HAVING amount != 0
|
|
577
|
-
ORDER BY a.code, a.name`
|
|
578
|
-
)
|
|
579
|
-
.all(...params) as { account_id: string; account_name: string; account_code: string | null; amount: number }[];
|
|
580
|
-
|
|
581
|
-
const totalRevenue = revenueRows.reduce((sum, r) => sum + r.amount, 0);
|
|
582
|
-
const totalExpenses = expenseRows.reduce((sum, r) => sum + r.amount, 0);
|
|
583
|
-
|
|
584
|
-
return {
|
|
585
|
-
revenue: revenueRows,
|
|
586
|
-
expenses: expenseRows,
|
|
587
|
-
total_revenue: Math.round(totalRevenue * 100) / 100,
|
|
588
|
-
total_expenses: Math.round(totalExpenses * 100) / 100,
|
|
589
|
-
net_income: Math.round((totalRevenue - totalExpenses) * 100) / 100,
|
|
590
|
-
};
|
|
591
|
-
}
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Database connection for microservice-bookkeeping
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { Database } from "bun:sqlite";
|
|
6
|
-
import { existsSync, mkdirSync } from "node:fs";
|
|
7
|
-
import { dirname, join, resolve } from "node:path";
|
|
8
|
-
import { MIGRATIONS } from "./migrations.js";
|
|
9
|
-
|
|
10
|
-
let _db: Database | null = null;
|
|
11
|
-
|
|
12
|
-
function getDbPath(): string {
|
|
13
|
-
// Environment variable override
|
|
14
|
-
if (process.env["MICROSERVICES_DIR"]) {
|
|
15
|
-
return join(process.env["MICROSERVICES_DIR"], "microservice-bookkeeping", "data.db");
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// Check for .microservices in current or parent directories
|
|
19
|
-
let dir = resolve(process.cwd());
|
|
20
|
-
while (true) {
|
|
21
|
-
const candidate = join(dir, ".microservices", "microservice-bookkeeping", "data.db");
|
|
22
|
-
const msDir = join(dir, ".microservices");
|
|
23
|
-
if (existsSync(msDir)) return candidate;
|
|
24
|
-
const parent = dirname(dir);
|
|
25
|
-
if (parent === dir) break;
|
|
26
|
-
dir = parent;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// Global fallback
|
|
30
|
-
const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
|
|
31
|
-
return join(home, ".microservices", "microservice-bookkeeping", "data.db");
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function ensureDir(filePath: string): void {
|
|
35
|
-
const dir = dirname(resolve(filePath));
|
|
36
|
-
if (!existsSync(dir)) {
|
|
37
|
-
mkdirSync(dir, { recursive: true });
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export function getDatabase(): Database {
|
|
42
|
-
if (_db) return _db;
|
|
43
|
-
|
|
44
|
-
const dbPath = getDbPath();
|
|
45
|
-
ensureDir(dbPath);
|
|
46
|
-
|
|
47
|
-
_db = new Database(dbPath);
|
|
48
|
-
_db.exec("PRAGMA journal_mode = WAL");
|
|
49
|
-
_db.exec("PRAGMA foreign_keys = ON");
|
|
50
|
-
|
|
51
|
-
// Create migrations table
|
|
52
|
-
_db.exec(`
|
|
53
|
-
CREATE TABLE IF NOT EXISTS _migrations (
|
|
54
|
-
id INTEGER PRIMARY KEY,
|
|
55
|
-
name TEXT NOT NULL,
|
|
56
|
-
applied_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
57
|
-
)
|
|
58
|
-
`);
|
|
59
|
-
|
|
60
|
-
// Apply pending migrations
|
|
61
|
-
const applied = _db
|
|
62
|
-
.query("SELECT id FROM _migrations ORDER BY id")
|
|
63
|
-
.all() as { id: number }[];
|
|
64
|
-
const appliedIds = new Set(applied.map((r) => r.id));
|
|
65
|
-
|
|
66
|
-
for (const migration of MIGRATIONS) {
|
|
67
|
-
if (appliedIds.has(migration.id)) continue;
|
|
68
|
-
|
|
69
|
-
_db.exec("BEGIN");
|
|
70
|
-
try {
|
|
71
|
-
_db.exec(migration.sql);
|
|
72
|
-
_db.prepare("INSERT INTO _migrations (id, name) VALUES (?, ?)").run(
|
|
73
|
-
migration.id,
|
|
74
|
-
migration.name
|
|
75
|
-
);
|
|
76
|
-
_db.exec("COMMIT");
|
|
77
|
-
} catch (error) {
|
|
78
|
-
_db.exec("ROLLBACK");
|
|
79
|
-
throw new Error(
|
|
80
|
-
`Migration ${migration.id} (${migration.name}) failed: ${error instanceof Error ? error.message : String(error)}`
|
|
81
|
-
);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return _db;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export function closeDatabase(): void {
|
|
89
|
-
if (_db) {
|
|
90
|
-
_db.close();
|
|
91
|
-
_db = null;
|
|
92
|
-
}
|
|
93
|
-
}
|