@happyvertical/smrt-cli 0.51.23 → 0.51.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/AGENTS.md +1 -0
  2. package/README.md +1 -0
  3. package/dist/{ApiKey-BZmbOTnL-Bo7tbG1k.js → ApiKey-BZmbOTnL-BHFzurt7.js} +2 -2
  4. package/dist/ApiKeyCollection-Bfb_nw81-D8b3Nrg4.js +2 -0
  5. package/dist/AuditLogCollection-B1YonCAP-CpPE8zro.js +2 -0
  6. package/dist/{NostrIdentity-n70E0vck-G4M4P2GW.js → NostrIdentity-n70E0vck-Cga1lWU1.js} +3 -3
  7. package/dist/NostrIdentityCollection-Ca74dkaL-BKzq1O2N.js +2 -0
  8. package/dist/{OidcIdentity-K8V4u0CR-D3Zc7yju.js → OidcIdentity-K8V4u0CR-buvSdd8D.js} +2 -2
  9. package/dist/OidcIdentityCollection-gnrLoF08-BsEJX0w8.js +2 -0
  10. package/dist/ProfileAssetCollection-CmbeSgDi-CcjX8UeG.js +2 -0
  11. package/dist/{ProfileCollection-DTT4KNpQ-CFn9nEde.js → ProfileCollection-DTT4KNpQ-B2yHjF8e.js} +30 -653
  12. package/dist/ProfileMetadataCollection-DxX_BJKV-CqTZZ7O9.js +2 -0
  13. package/dist/{ProfileMetafieldCollection-CMKhVi2I-NPA4NfPL.js → ProfileMetafieldCollection-CMKhVi2I-BTguykyW.js} +1 -1
  14. package/dist/{ProfileRelationshipCollection-DUVgaIqf-BlH89282.js → ProfileRelationshipCollection-DUVgaIqf-CdOJCU07.js} +1 -1
  15. package/dist/{ProfileRelationshipTermCollection-DtA9OM23-D3KSY2OS.js → ProfileRelationshipTermCollection-DtA9OM23-ug8uUFUp.js} +1 -1
  16. package/dist/{ProfileRelationshipType-BRiRka6t-sguU4oDf.js → ProfileRelationshipType-BRiRka6t-B-lkyTB2.js} +1 -1
  17. package/dist/{ProfileRelationshipTypeCollection-BdXwd7Kf-DGHj5NYL.js → ProfileRelationshipTypeCollection-BdXwd7Kf-BUuZ3P72.js} +1 -1
  18. package/dist/{commands-CdijcyQl.js → commands-BVFlmHkE.js} +61 -1
  19. package/dist/dist-4XD0OZmB.js +1235 -0
  20. package/dist/dist-C-AYkaoT.js +813 -0
  21. package/dist/{dist-DPN8zVvb.js → dist-CaxtTrhT.js} +3 -3
  22. package/dist/{dist-Cm7M-US-.js → dist-VEFJWHIY.js} +25 -25
  23. package/dist/index.js +9 -9
  24. package/dist/{oidcProvisioningPrimitives-0-3n3D6f-2uN0TAcP.js → oidcProvisioningPrimitives-0-3n3D6f-DpuGh5Ac.js} +4 -4
  25. package/dist/resolveIdentity-BrJDCjYi-DrBA1wFo.js +2 -0
  26. package/package.json +9 -8
  27. package/dist/ApiKeyCollection-Bfb_nw81-CNAaLULe.js +0 -2
  28. package/dist/AuditLogCollection-B1YonCAP-yweHrz14.js +0 -2
  29. package/dist/NostrIdentityCollection-Ca74dkaL-aM_-cerc.js +0 -2
  30. package/dist/OidcIdentityCollection-gnrLoF08-B5y4FHI0.js +0 -2
  31. package/dist/ProfileAssetCollection-CmbeSgDi-mMSqxPLS.js +0 -2
  32. package/dist/ProfileMetadataCollection-DxX_BJKV-CXKXBRtU.js +0 -2
  33. package/dist/dist-B5ngi39H.js +0 -190
  34. package/dist/resolveIdentity-BrJDCjYi-CX_TCtNl.js +0 -2
@@ -0,0 +1,1235 @@
1
+ import { a as queryGlobal, i as tenantId, n as resolvePrompt, o as queryWithGlobals, r as TenantScoped, t as definePrompt } from "./dist-C-AYkaoT.js";
2
+ import { ObjectRegistry, SmrtCollection, SmrtHierarchical, SmrtObject, detectEngine, foreignKey, smrt } from "@happyvertical/smrt-core";
3
+ import { BackfillTracker } from "@happyvertical/smrt-core/migrations";
4
+ //#region ../ledgers/dist/chunks/Account-Dr4tA_Gn.js
5
+ var __defProp$3 = Object.defineProperty;
6
+ var __getOwnPropDesc$2 = Object.getOwnPropertyDescriptor;
7
+ var __decorateClass$2 = (decorators, target, key, kind) => {
8
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$2(target, key) : target;
9
+ for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
10
+ if (kind && result) __defProp$3(target, key, result);
11
+ return result;
12
+ };
13
+ var Account = class extends SmrtHierarchical {
14
+ tenantId = null;
15
+ /**
16
+ * Account number (e.g., "1000", "5030")
17
+ */
18
+ number = "";
19
+ /**
20
+ * Account name (e.g., "Cash", "Coffee Expense")
21
+ */
22
+ name = "";
23
+ /**
24
+ * Account description
25
+ */
26
+ description = "";
27
+ /**
28
+ * Account type - one of the 5 core types
29
+ */
30
+ type = "asset";
31
+ /**
32
+ * Whether the account is active
33
+ */
34
+ active = true;
35
+ /**
36
+ * Extensible metadata
37
+ */
38
+ metadata = {};
39
+ constructor(options = {}) {
40
+ super(options);
41
+ if (options.number !== void 0) this.number = options.number;
42
+ if (options.name !== void 0) this.name = options.name;
43
+ if (options.description !== void 0) this.description = options.description;
44
+ if (options.type !== void 0) this.type = options.type;
45
+ if (options.parentId !== void 0) this.parentId = options.parentId;
46
+ if (options.active !== void 0) this.active = options.active;
47
+ if (options.metadata !== void 0) this.metadata = options.metadata;
48
+ }
49
+ /**
50
+ * Check if this is a top-level account (no parent)
51
+ */
52
+ isTopLevel() {
53
+ return this.parentId === null;
54
+ }
55
+ /**
56
+ * Check if this is a debit-normal account (Asset, Expense)
57
+ * Debit-normal accounts increase with debits
58
+ */
59
+ isDebitNormal() {
60
+ return this.type === "asset" || this.type === "expense";
61
+ }
62
+ /**
63
+ * Check if this is a credit-normal account (Liability, Equity, Revenue)
64
+ * Credit-normal accounts increase with credits
65
+ */
66
+ isCreditNormal() {
67
+ return this.type === "liability" || this.type === "equity" || this.type === "revenue";
68
+ }
69
+ /**
70
+ * Get full account path (e.g., "Assets > Current > Cash")
71
+ */
72
+ async getFullPath() {
73
+ return [...(await this.getAncestors()).map((a) => a.name), this.name].join(" > ");
74
+ }
75
+ /**
76
+ * Build tree node for this account and its children
77
+ */
78
+ async toTreeNode() {
79
+ const children = await this.getChildren();
80
+ const childNodes = await Promise.all(children.map((c) => c.toTreeNode()));
81
+ return {
82
+ account: this,
83
+ children: childNodes
84
+ };
85
+ }
86
+ /**
87
+ * Get the current balance of this account
88
+ */
89
+ async getBalance(asOfDate) {
90
+ if (!this.id) return 0;
91
+ const { JournalEntryCollection } = await import("./dist-4XD0OZmB.js").then((n) => n.t);
92
+ return await (await JournalEntryCollection.create(this.options)).getAccountBalance(this.id, asOfDate);
93
+ }
94
+ /**
95
+ * Create a sub-account under this account
96
+ */
97
+ async createChild(options) {
98
+ if (!this.id) throw new Error("Account must be saved before creating children");
99
+ const { AccountCollection } = await import("./dist-4XD0OZmB.js").then((n) => n.n);
100
+ const account = await (await AccountCollection.create(this.options)).create({
101
+ ...options,
102
+ parentId: this.id,
103
+ type: this.type
104
+ });
105
+ await account.save();
106
+ return account;
107
+ }
108
+ };
109
+ __decorateClass$2([tenantId({ nullable: true })], Account.prototype, "tenantId", 2);
110
+ Account = __decorateClass$2([TenantScoped({ mode: "optional" }), smrt({
111
+ tableName: "ledger_accounts",
112
+ api: { include: [
113
+ "list",
114
+ "get",
115
+ "create",
116
+ "update",
117
+ "delete"
118
+ ] },
119
+ mcp: { include: [
120
+ "list",
121
+ "get",
122
+ "create"
123
+ ] },
124
+ cli: { skipApiCheck: true }
125
+ })], Account);
126
+ //#endregion
127
+ //#region ../ledgers/dist/types.js
128
+ var BALANCE_EPSILON = .001;
129
+ //#endregion
130
+ //#region ../ledgers/dist/index.js
131
+ var __defProp$2 = Object.defineProperty;
132
+ var __exportAll = (all, no_symbols) => {
133
+ let target = {};
134
+ for (var name in all) __defProp$2(target, name, {
135
+ get: all[name],
136
+ enumerable: true
137
+ });
138
+ if (!no_symbols) __defProp$2(target, Symbol.toStringTag, { value: "Module" });
139
+ return target;
140
+ };
141
+ ObjectRegistry.registerPackageManifest(JSON.parse("{\"version\":\"1.0.0\",\"timestamp\":0,\"packageName\":\"@happyvertical/smrt-ledgers\",\"packageVersion\":\"0.51.25\",\"objects\":{\"@happyvertical/smrt-ledgers:AccountCollection\":{\"name\":\"accountcollection\",\"className\":\"AccountCollection\",\"qualifiedName\":\"@happyvertical/smrt-ledgers:AccountCollection\",\"collection\":\"accounts\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/ledgers/src/collections/Accounts.ts\",\"packageName\":\"@happyvertical/smrt-ledgers\",\"fields\":{},\"methods\":{\"findByNumber\":{\"name\":\"findByNumber\",\"async\":true,\"parameters\":[{\"name\":\"number\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Account | null>\",\"isStatic\":false,\"isPublic\":true},\"findByType\":{\"name\":\"findByType\",\"async\":true,\"parameters\":[{\"name\":\"type\",\"type\":\"AccountType\",\"optional\":false}],\"returnType\":\"Promise<Account[]>\",\"isStatic\":false,\"isPublic\":true},\"findActive\":{\"name\":\"findActive\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Account[]>\",\"isStatic\":false,\"isPublic\":true},\"findTopLevel\":{\"name\":\"findTopLevel\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Account[]>\",\"isStatic\":false,\"isPublic\":true},\"findChildren\":{\"name\":\"findChildren\",\"async\":true,\"parameters\":[{\"name\":\"parentId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Account[]>\",\"isStatic\":false,\"isPublic\":true},\"getTree\":{\"name\":\"getTree\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<AccountTree>\",\"isStatic\":false,\"isPublic\":true},\"getOrCreateByNumber\":{\"name\":\"getOrCreateByNumber\",\"async\":true,\"parameters\":[{\"name\":\"number\",\"type\":\"string\",\"optional\":false},{\"name\":\"defaults\",\"type\":\"Partial<object>\",\"optional\":true,\"memberTypes\":[\"string\",\"AccountType\",\"string | null\"]}],\"returnType\":\"Promise<Account>\",\"isStatic\":false,\"isPublic\":true},\"groupByType\":{\"name\":\"groupByType\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Record<AccountType, Account[]>>\",\"isStatic\":false,\"isPublic\":true},\"getDescendants\":{\"name\":\"getDescendants\",\"async\":true,\"parameters\":[{\"name\":\"accountId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Account[]>\",\"isStatic\":false,\"isPublic\":true},\"findByTenant\":{\"name\":\"findByTenant\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Account[]>\",\"isStatic\":false,\"isPublic\":true},\"findGlobal\":{\"name\":\"findGlobal\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Account[]>\",\"isStatic\":false,\"isPublic\":true},\"findWithGlobals\":{\"name\":\"findWithGlobals\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Account[]>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"ledger_accounts\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"Account\",\"exportName\":\"AccountCollection\",\"collectionExportName\":\"AccountCollectionCollection\",\"schema\":{\"tableName\":\"ledger_accounts\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"ledger_accounts\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"parent_id\\\" UUID,\\n \\\"tenant_id\\\" UUID,\\n \\\"number\\\" TEXT DEFAULT '',\\n \\\"name\\\" TEXT DEFAULT '',\\n \\\"description\\\" TEXT DEFAULT '',\\n \\\"type\\\" TEXT DEFAULT 'asset',\\n \\\"active\\\" BOOLEAN DEFAULT TRUE,\\n \\\"metadata\\\" JSON DEFAULT '{}'\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"parent_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"unique\":false,\"foreignKey\":{\"table\":\"ledger_accounts\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"number\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"name\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"description\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"type\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"asset\"},\"active\":{\"type\":\"BOOLEAN\",\"notNull\":false,\"unique\":false,\"default\":true},\"metadata\":{\"type\":\"JSON\",\"notNull\":false,\"unique\":false,\"default\":{}}},\"indexes\":[{\"name\":\"ledger_accounts_slug_context_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"ledger_accounts_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"ledger_accounts_parent_id_idx\",\"columns\":[\"parent_id\"]}],\"version\":\"49630dae\"},\"importPath\":\"@happyvertical/smrt-ledgers\"},\"@happyvertical/smrt-ledgers:JournalEntryCollection\":{\"name\":\"journalentrycollection\",\"className\":\"JournalEntryCollection\",\"qualifiedName\":\"@happyvertical/smrt-ledgers:JournalEntryCollection\",\"collection\":\"journalentries\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/ledgers/src/collections/JournalEntries.ts\",\"packageName\":\"@happyvertical/smrt-ledgers\",\"fields\":{},\"methods\":{\"findByJournal\":{\"name\":\"findByJournal\",\"async\":true,\"parameters\":[{\"name\":\"journalId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<JournalEntry[]>\",\"isStatic\":false,\"isPublic\":true},\"findByAccount\":{\"name\":\"findByAccount\",\"async\":true,\"parameters\":[{\"name\":\"accountId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<JournalEntry[]>\",\"isStatic\":false,\"isPublic\":true},\"getAccountBalance\":{\"name\":\"getAccountBalance\",\"async\":true,\"parameters\":[{\"name\":\"accountId\",\"type\":\"string\",\"optional\":false},{\"name\":\"asOfDate\",\"type\":\"Date\",\"optional\":true}],\"returnType\":\"Promise<number>\",\"isStatic\":false,\"isPublic\":true},\"getTrialBalance\":{\"name\":\"getTrialBalance\",\"async\":true,\"parameters\":[{\"name\":\"asOfDate\",\"type\":\"Date\",\"optional\":true}],\"returnType\":\"Promise<TrialBalanceRow[]>\",\"isStatic\":false,\"isPublic\":true},\"getTotalsForDateRange\":{\"name\":\"getTotalsForDateRange\",\"async\":true,\"parameters\":[{\"name\":\"start\",\"type\":\"Date\",\"optional\":false},{\"name\":\"end\",\"type\":\"Date\",\"optional\":false}],\"returnType\":\"Promise<object>\",\"isStatic\":false,\"isPublic\":true},\"findByAccounts\":{\"name\":\"findByAccounts\",\"async\":true,\"parameters\":[{\"name\":\"accountIds\",\"type\":\"string[]\",\"optional\":false}],\"returnType\":\"Promise<JournalEntry[]>\",\"isStatic\":false,\"isPublic\":true},\"getAccountLedger\":{\"name\":\"getAccountLedger\",\"async\":true,\"parameters\":[{\"name\":\"accountId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Array<object>>\",\"isStatic\":false,\"isPublic\":true},\"findByTenant\":{\"name\":\"findByTenant\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<JournalEntry[]>\",\"isStatic\":false,\"isPublic\":true},\"findGlobal\":{\"name\":\"findGlobal\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<JournalEntry[]>\",\"isStatic\":false,\"isPublic\":true},\"findWithGlobals\":{\"name\":\"findWithGlobals\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<JournalEntry[]>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"JournalEntry\",\"exportName\":\"JournalEntryCollection\",\"collectionExportName\":\"JournalEntryCollectionCollection\",\"schema\":{\"tableName\":\"journal_entries\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"journal_entries\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"journal_id\\\" UUID,\\n \\\"account_id\\\" UUID,\\n \\\"debit\\\" REAL DEFAULT 0,\\n \\\"credit\\\" REAL DEFAULT 0,\\n \\\"currency\\\" TEXT DEFAULT 'USD',\\n \\\"exchange_rate\\\" REAL DEFAULT 1,\\n \\\"memo\\\" TEXT DEFAULT '',\\n \\\"metadata\\\" JSON DEFAULT '{}'\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"journal_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"unique\":false,\"foreignKey\":{\"table\":\"journals\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"account_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"unique\":false,\"foreignKey\":{\"table\":\"ledger_accounts\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"debit\":{\"type\":\"REAL\",\"notNull\":false,\"unique\":false,\"default\":0},\"credit\":{\"type\":\"REAL\",\"notNull\":false,\"unique\":false,\"default\":0},\"currency\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"USD\"},\"exchange_rate\":{\"type\":\"REAL\",\"notNull\":false,\"unique\":false,\"default\":1},\"memo\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"metadata\":{\"type\":\"JSON\",\"notNull\":false,\"unique\":false,\"default\":{}}},\"indexes\":[{\"name\":\"journal_entries_slug_context_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"journal_entries_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"journal_entries_journal_id_idx\",\"columns\":[\"journal_id\"]},{\"name\":\"journal_entries_account_id_idx\",\"columns\":[\"account_id\"]}],\"version\":\"93cdc848\"},\"importPath\":\"@happyvertical/smrt-ledgers\"},\"@happyvertical/smrt-ledgers:JournalCollection\":{\"name\":\"journalcollection\",\"className\":\"JournalCollection\",\"qualifiedName\":\"@happyvertical/smrt-ledgers:JournalCollection\",\"collection\":\"journals\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/ledgers/src/collections/Journals.ts\",\"packageName\":\"@happyvertical/smrt-ledgers\",\"fields\":{},\"methods\":{\"findByNumber\":{\"name\":\"findByNumber\",\"async\":true,\"parameters\":[{\"name\":\"number\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Journal | null>\",\"isStatic\":false,\"isPublic\":true},\"findByDateRange\":{\"name\":\"findByDateRange\",\"async\":true,\"parameters\":[{\"name\":\"start\",\"type\":\"Date\",\"optional\":false},{\"name\":\"end\",\"type\":\"Date\",\"optional\":false}],\"returnType\":\"Promise<Journal[]>\",\"isStatic\":false,\"isPublic\":true},\"findBySource\":{\"name\":\"findBySource\",\"async\":true,\"parameters\":[{\"name\":\"sourceModule\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Journal[]>\",\"isStatic\":false,\"isPublic\":true},\"findByStatus\":{\"name\":\"findByStatus\",\"async\":true,\"parameters\":[{\"name\":\"status\",\"type\":\"JournalStatus\",\"optional\":false}],\"returnType\":\"Promise<Journal[]>\",\"isStatic\":false,\"isPublic\":true},\"findDrafts\":{\"name\":\"findDrafts\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Journal[]>\",\"isStatic\":false,\"isPublic\":true},\"findPosted\":{\"name\":\"findPosted\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Journal[]>\",\"isStatic\":false,\"isPublic\":true},\"createWithEntries\":{\"name\":\"createWithEntries\",\"async\":true,\"parameters\":[{\"name\":\"data\",\"type\":\"CreateJournalData\",\"optional\":false}],\"returnType\":\"Promise<Journal>\",\"isStatic\":false,\"isPublic\":true},\"post\":{\"name\":\"post\",\"async\":true,\"parameters\":[{\"name\":\"journalId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Journal>\",\"isStatic\":false,\"isPublic\":true},\"void\":{\"name\":\"void\",\"async\":true,\"parameters\":[{\"name\":\"journalId\",\"type\":\"string\",\"optional\":false},{\"name\":\"reason\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Journal>\",\"isStatic\":false,\"isPublic\":true},\"findBySourceRef\":{\"name\":\"findBySourceRef\",\"async\":true,\"parameters\":[{\"name\":\"sourceRef\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Journal[]>\",\"isStatic\":false,\"isPublic\":true},\"findByMonth\":{\"name\":\"findByMonth\",\"async\":true,\"parameters\":[{\"name\":\"year\",\"type\":\"number\",\"optional\":false},{\"name\":\"month\",\"type\":\"number\",\"optional\":false}],\"returnType\":\"Promise<Journal[]>\",\"isStatic\":false,\"isPublic\":true},\"findByTenant\":{\"name\":\"findByTenant\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Journal[]>\",\"isStatic\":false,\"isPublic\":true},\"findGlobal\":{\"name\":\"findGlobal\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Journal[]>\",\"isStatic\":false,\"isPublic\":true},\"findWithGlobals\":{\"name\":\"findWithGlobals\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Journal[]>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"Journal\",\"exportName\":\"JournalCollection\",\"collectionExportName\":\"JournalCollectionCollection\",\"schema\":{\"tableName\":\"journals\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"journals\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"number\\\" TEXT DEFAULT '',\\n \\\"date\\\" TIMESTAMP,\\n \\\"description\\\" TEXT DEFAULT '',\\n \\\"source_module\\\" TEXT DEFAULT '',\\n \\\"source_ref\\\" TEXT,\\n \\\"status\\\" TEXT DEFAULT 'draft',\\n \\\"posted_at\\\" TIMESTAMP,\\n \\\"voided_at\\\" TIMESTAMP,\\n \\\"void_reason\\\" TEXT,\\n \\\"metadata\\\" JSON DEFAULT '{}'\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"number\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"date\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"description\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"source_module\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"source_ref\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"status\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"draft\"},\"posted_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"voided_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"void_reason\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"metadata\":{\"type\":\"JSON\",\"notNull\":false,\"unique\":false,\"default\":{}}},\"indexes\":[{\"name\":\"journals_slug_context_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"journals_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]}],\"version\":\"4b51d204\"},\"importPath\":\"@happyvertical/smrt-ledgers\"},\"@happyvertical/smrt-ledgers:Account\":{\"name\":\"account\",\"className\":\"Account\",\"qualifiedName\":\"@happyvertical/smrt-ledgers:Account\",\"collection\":\"accounts\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/ledgers/src/models/Account.ts\",\"packageName\":\"@happyvertical/smrt-ledgers\",\"fields\":{\"parentId\":{\"type\":\"foreignKey\",\"required\":false,\"related\":\"Account\",\"_meta\":{\"nullable\":true}},\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"number\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"name\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"description\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"type\":{\"type\":\"text\",\"required\":false,\"default\":\"asset\"},\"active\":{\"type\":\"boolean\",\"required\":false,\"default\":true},\"metadata\":{\"type\":\"json\",\"required\":false,\"default\":{}}},\"methods\":{\"getParent\":{\"name\":\"getParent\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<this | null>\",\"isStatic\":false,\"isPublic\":true},\"getChildren\":{\"name\":\"getChildren\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<this[]>\",\"isStatic\":false,\"isPublic\":true},\"getAncestors\":{\"name\":\"getAncestors\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<this[]>\",\"isStatic\":false,\"isPublic\":true},\"getDescendants\":{\"name\":\"getDescendants\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<this[]>\",\"isStatic\":false,\"isPublic\":true},\"getHierarchy\":{\"name\":\"getHierarchy\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<HierarchyView<this>>\",\"isStatic\":false,\"isPublic\":true},\"moveTo\":{\"name\":\"moveTo\",\"async\":true,\"parameters\":[{\"name\":\"newParent\",\"type\":\"this | string | null\",\"optional\":false,\"unionBranches\":[{\"type\":\"this\"},{\"type\":\"string\"},{\"type\":\"null\"}]}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"isTopLevel\":{\"name\":\"isTopLevel\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"isDebitNormal\":{\"name\":\"isDebitNormal\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"isCreditNormal\":{\"name\":\"isCreditNormal\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"getFullPath\":{\"name\":\"getFullPath\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<string>\",\"isStatic\":false,\"isPublic\":true},\"toTreeNode\":{\"name\":\"toTreeNode\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<AccountTreeNode>\",\"isStatic\":false,\"isPublic\":true},\"getBalance\":{\"name\":\"getBalance\",\"async\":true,\"parameters\":[{\"name\":\"asOfDate\",\"type\":\"Date\",\"optional\":true}],\"returnType\":\"Promise<number>\",\"isStatic\":false,\"isPublic\":true},\"createChild\":{\"name\":\"createChild\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"Omit<AccountOptions, 'parentId' | 'type'>\",\"optional\":false}],\"returnType\":\"Promise<Account>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"ledger_accounts\",\"api\":{\"include\":[\"list\",\"get\",\"create\",\"update\",\"delete\"]},\"mcp\":{\"include\":[\"list\",\"get\",\"create\"]},\"cli\":{\"skipApiCheck\":true},\"tenantScoped\":{\"mode\":\"optional\"},\"conflictColumns\":[\"tenant_id\",\"slug\",\"context\"]},\"extends\":\"SmrtHierarchical\",\"exportName\":\"Account\",\"collectionExportName\":\"AccountCollection\",\"schema\":{\"tableName\":\"ledger_accounts\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"ledger_accounts\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"parent_id\\\" UUID,\\n \\\"tenant_id\\\" UUID,\\n \\\"number\\\" TEXT DEFAULT '',\\n \\\"name\\\" TEXT DEFAULT '',\\n \\\"description\\\" TEXT DEFAULT '',\\n \\\"type\\\" TEXT DEFAULT 'asset',\\n \\\"active\\\" BOOLEAN DEFAULT TRUE,\\n \\\"metadata\\\" JSON DEFAULT '{}'\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"parent_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"unique\":false,\"foreignKey\":{\"table\":\"ledger_accounts\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"number\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"name\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"description\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"type\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"asset\"},\"active\":{\"type\":\"BOOLEAN\",\"notNull\":false,\"unique\":false,\"default\":true},\"metadata\":{\"type\":\"JSON\",\"notNull\":false,\"unique\":false,\"default\":{}}},\"indexes\":[{\"name\":\"ledger_accounts_slug_context_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"ledger_accounts_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"ledger_accounts_parent_id_idx\",\"columns\":[\"parent_id\"]}],\"version\":\"49630dae\"},\"importPath\":\"@happyvertical/smrt-ledgers\"},\"@happyvertical/smrt-ledgers:Journal\":{\"name\":\"journal\",\"className\":\"Journal\",\"qualifiedName\":\"@happyvertical/smrt-ledgers:Journal\",\"collection\":\"journals\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/ledgers/src/models/Journal.ts\",\"packageName\":\"@happyvertical/smrt-ledgers\",\"fields\":{\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"number\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"date\":{\"type\":\"datetime\",\"required\":false},\"description\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"sourceModule\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"sourceRef\":{\"type\":\"text\",\"required\":false},\"status\":{\"type\":\"text\",\"required\":false,\"default\":\"draft\"},\"postedAt\":{\"type\":\"datetime\",\"required\":false},\"voidedAt\":{\"type\":\"datetime\",\"required\":false},\"voidReason\":{\"type\":\"text\",\"required\":false},\"metadata\":{\"type\":\"json\",\"required\":false,\"default\":{}}},\"methods\":{\"isDraft\":{\"name\":\"isDraft\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"isPosted\":{\"name\":\"isPosted\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"isVoided\":{\"name\":\"isVoided\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"isEditable\":{\"name\":\"isEditable\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"getEntries\":{\"name\":\"getEntries\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getTotalDebits\":{\"name\":\"getTotalDebits\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<number>\",\"isStatic\":false,\"isPublic\":true},\"getTotalCredits\":{\"name\":\"getTotalCredits\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<number>\",\"isStatic\":false,\"isPublic\":true},\"isBalanced\":{\"name\":\"isBalanced\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<boolean>\",\"isStatic\":false,\"isPublic\":true},\"addEntry\":{\"name\":\"addEntry\",\"async\":true,\"parameters\":[{\"name\":\"data\",\"type\":\"JournalEntryData\",\"optional\":false}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"post\":{\"name\":\"post\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"void\":{\"name\":\"void\",\"async\":true,\"parameters\":[{\"name\":\"reason\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"summarize\":{\"name\":\"summarize\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<string>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"api\":{\"include\":[\"list\",\"get\",\"create\"]},\"mcp\":{\"include\":[\"list\",\"get\",\"create\"]},\"cli\":{\"skipApiCheck\":true},\"tenantScoped\":{\"mode\":\"optional\"},\"conflictColumns\":[\"tenant_id\",\"slug\",\"context\"]},\"extends\":\"SmrtObject\",\"exportName\":\"Journal\",\"collectionExportName\":\"JournalCollection\",\"schema\":{\"tableName\":\"journals\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"journals\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"number\\\" TEXT DEFAULT '',\\n \\\"date\\\" TIMESTAMP,\\n \\\"description\\\" TEXT DEFAULT '',\\n \\\"source_module\\\" TEXT DEFAULT '',\\n \\\"source_ref\\\" TEXT,\\n \\\"status\\\" TEXT DEFAULT 'draft',\\n \\\"posted_at\\\" TIMESTAMP,\\n \\\"voided_at\\\" TIMESTAMP,\\n \\\"void_reason\\\" TEXT,\\n \\\"metadata\\\" JSON DEFAULT '{}'\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"number\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"date\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"description\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"source_module\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"source_ref\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"status\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"draft\"},\"posted_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"voided_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"void_reason\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"metadata\":{\"type\":\"JSON\",\"notNull\":false,\"unique\":false,\"default\":{}}},\"indexes\":[{\"name\":\"journals_slug_context_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"journals_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]}],\"version\":\"4b51d204\"},\"importPath\":\"@happyvertical/smrt-ledgers\"},\"@happyvertical/smrt-ledgers:JournalEntry\":{\"name\":\"journalentry\",\"className\":\"JournalEntry\",\"qualifiedName\":\"@happyvertical/smrt-ledgers:JournalEntry\",\"collection\":\"journalentries\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/ledgers/src/models/JournalEntry.ts\",\"packageName\":\"@happyvertical/smrt-ledgers\",\"fields\":{\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"journalId\":{\"type\":\"foreignKey\",\"required\":false,\"related\":\"Journal\"},\"accountId\":{\"type\":\"foreignKey\",\"required\":false,\"related\":\"Account\"},\"debit\":{\"type\":\"decimal\",\"required\":false,\"default\":0},\"credit\":{\"type\":\"decimal\",\"required\":false,\"default\":0},\"currency\":{\"type\":\"text\",\"required\":false,\"default\":\"USD\"},\"exchangeRate\":{\"type\":\"decimal\",\"required\":false,\"default\":1},\"memo\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"metadata\":{\"type\":\"json\",\"required\":false,\"default\":{}}},\"methods\":{\"isDebit\":{\"name\":\"isDebit\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"isCredit\":{\"name\":\"isCredit\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"getAmount\":{\"name\":\"getAmount\",\"async\":false,\"parameters\":[],\"returnType\":\"number\",\"isStatic\":false,\"isPublic\":true},\"getBaseAmount\":{\"name\":\"getBaseAmount\",\"async\":false,\"parameters\":[],\"returnType\":\"number\",\"isStatic\":false,\"isPublic\":true},\"getJournal\":{\"name\":\"getJournal\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getAccount\":{\"name\":\"getAccount\",\"async\":true,\"parameters\":[],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true},\"getDescription\":{\"name\":\"getDescription\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<string>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"api\":{\"include\":[\"list\",\"get\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"cli\":{\"skipApiCheck\":true},\"tenantScoped\":{\"mode\":\"optional\"},\"conflictColumns\":[\"tenant_id\",\"slug\",\"context\"]},\"extends\":\"SmrtObject\",\"exportName\":\"JournalEntry\",\"collectionExportName\":\"JournalEntryCollection\",\"schema\":{\"tableName\":\"journal_entries\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"journal_entries\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"journal_id\\\" UUID,\\n \\\"account_id\\\" UUID,\\n \\\"debit\\\" REAL DEFAULT 0,\\n \\\"credit\\\" REAL DEFAULT 0,\\n \\\"currency\\\" TEXT DEFAULT 'USD',\\n \\\"exchange_rate\\\" REAL DEFAULT 1,\\n \\\"memo\\\" TEXT DEFAULT '',\\n \\\"metadata\\\" JSON DEFAULT '{}'\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"journal_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"unique\":false,\"foreignKey\":{\"table\":\"journals\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"account_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"unique\":false,\"foreignKey\":{\"table\":\"ledger_accounts\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"debit\":{\"type\":\"REAL\",\"notNull\":false,\"unique\":false,\"default\":0},\"credit\":{\"type\":\"REAL\",\"notNull\":false,\"unique\":false,\"default\":0},\"currency\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"USD\"},\"exchange_rate\":{\"type\":\"REAL\",\"notNull\":false,\"unique\":false,\"default\":1},\"memo\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"metadata\":{\"type\":\"JSON\",\"notNull\":false,\"unique\":false,\"default\":{}}},\"indexes\":[{\"name\":\"journal_entries_slug_context_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"journal_entries_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"journal_entries_journal_id_idx\",\"columns\":[\"journal_id\"]},{\"name\":\"journal_entries_account_id_idx\",\"columns\":[\"account_id\"]}],\"version\":\"93cdc848\"},\"importPath\":\"@happyvertical/smrt-ledgers\"}},\"moduleType\":\"smrt\",\"smrtDependencies\":[\"@happyvertical/smrt-core\",\"@happyvertical/smrt-prompts\",\"@happyvertical/smrt-tenancy\"]}"));
142
+ var smrtLedgersJournalSummarizePrompt = definePrompt({
143
+ key: "smrtLedgers.journal.summarize",
144
+ template: `Summarize this accounting journal entry:
145
+ Number: {journalNumber}
146
+ Date: {journalDate}
147
+ Description: {journalDescription}
148
+ Status: {journalStatus}
149
+ Total: {journalTotal}
150
+ Entries: {entryCount}
151
+ Balanced: {journalBalanced}`,
152
+ editable: {
153
+ template: true,
154
+ profile: true,
155
+ model: true,
156
+ params: true
157
+ }
158
+ });
159
+ function promptMessageOptions(ai) {
160
+ return {
161
+ ...ai.params || {},
162
+ ...ai.model ? { model: ai.model } : {},
163
+ ...typeof ai.temperature === "number" ? { temperature: ai.temperature } : {},
164
+ ...typeof ai.maxTokens === "number" ? { maxTokens: ai.maxTokens } : {}
165
+ };
166
+ }
167
+ var Accounts_exports = /* @__PURE__ */ __exportAll({ AccountCollection: () => AccountCollection });
168
+ var AccountCollection = class extends SmrtCollection {
169
+ static _itemClass = Account;
170
+ /**
171
+ * Find account by number
172
+ *
173
+ * @param number - Account number
174
+ * @returns Account or null
175
+ */
176
+ async findByNumber(number) {
177
+ return (await this.list({
178
+ where: { number },
179
+ limit: 1
180
+ }))[0] || null;
181
+ }
182
+ /**
183
+ * Find accounts by type
184
+ *
185
+ * @param type - Account type
186
+ * @returns Array of accounts
187
+ */
188
+ async findByType(type) {
189
+ return await this.list({
190
+ where: { type },
191
+ orderBy: "number ASC"
192
+ });
193
+ }
194
+ /**
195
+ * Find all active accounts
196
+ *
197
+ * @returns Array of active accounts
198
+ */
199
+ async findActive() {
200
+ return await this.list({
201
+ where: { active: true },
202
+ orderBy: "number ASC"
203
+ });
204
+ }
205
+ /**
206
+ * Find top-level accounts (no parent)
207
+ *
208
+ * @returns Array of top-level accounts
209
+ */
210
+ async findTopLevel() {
211
+ return await this.list({
212
+ where: { parentId: null },
213
+ orderBy: "number ASC"
214
+ });
215
+ }
216
+ /**
217
+ * Find direct children of an account
218
+ *
219
+ * @param parentId - Parent account ID
220
+ * @returns Array of child accounts
221
+ */
222
+ async findChildren(parentId) {
223
+ return await this.list({
224
+ where: { parentId },
225
+ orderBy: "number ASC"
226
+ });
227
+ }
228
+ /**
229
+ * Get the complete account tree
230
+ *
231
+ * @returns AccountTree structure
232
+ */
233
+ async getTree() {
234
+ const allAccounts = await this.list({ orderBy: "number ASC" });
235
+ const accountMap = /* @__PURE__ */ new Map();
236
+ const childrenMap = /* @__PURE__ */ new Map();
237
+ for (const account of allAccounts) {
238
+ if (account.id) accountMap.set(account.id, account);
239
+ if (!childrenMap.has(account.parentId || "")) childrenMap.set(account.parentId || "", []);
240
+ childrenMap.get(account.parentId || "")?.push(account);
241
+ }
242
+ const buildNode = (account) => {
243
+ return {
244
+ account,
245
+ children: ((account.id ? childrenMap.get(account.id) : []) || []).map(buildNode)
246
+ };
247
+ };
248
+ return { roots: (childrenMap.get("") || []).map(buildNode) };
249
+ }
250
+ /**
251
+ * Get or create an account by number
252
+ *
253
+ * @param number - Account number
254
+ * @param defaults - Default values if creating
255
+ * @returns Account
256
+ */
257
+ async getOrCreateByNumber(number, defaults = {}) {
258
+ const existing = await this.findByNumber(number);
259
+ if (existing) return existing;
260
+ const account = await this.create({
261
+ number,
262
+ name: defaults.name || number,
263
+ description: defaults.description || "",
264
+ type: defaults.type || "asset",
265
+ parentId: defaults.parentId || null
266
+ });
267
+ await account.save();
268
+ return account;
269
+ }
270
+ /**
271
+ * Find accounts grouped by type
272
+ *
273
+ * @returns Record of type to accounts array
274
+ */
275
+ async groupByType() {
276
+ const accounts = await this.findActive();
277
+ const grouped = {
278
+ asset: [],
279
+ liability: [],
280
+ equity: [],
281
+ revenue: [],
282
+ expense: []
283
+ };
284
+ for (const account of accounts) grouped[account.type].push(account);
285
+ return grouped;
286
+ }
287
+ /**
288
+ * Get all descendants of an account recursively
289
+ *
290
+ * @param accountId - Account ID
291
+ * @returns Array of all descendant accounts
292
+ */
293
+ async getDescendants(accountId) {
294
+ const descendants = [];
295
+ const queue = [accountId];
296
+ while (queue.length > 0) {
297
+ const currentId = queue.shift();
298
+ if (!currentId) continue;
299
+ const children = await this.findChildren(currentId);
300
+ for (const child of children) {
301
+ descendants.push(child);
302
+ if (child.id) queue.push(child.id);
303
+ }
304
+ }
305
+ return descendants;
306
+ }
307
+ /**
308
+ * Find all accounts belonging to a specific tenant
309
+ *
310
+ * @param tenantId - Tenant ID
311
+ * @returns Array of tenant's accounts
312
+ */
313
+ async findByTenant(tenantId) {
314
+ return this.list({ where: { tenantId } });
315
+ }
316
+ /**
317
+ * Find all global accounts (no tenant association).
318
+ *
319
+ * Routes through the shared tenant-global helper so it does not throw under
320
+ * an active tenant context (an explicit `tenant_id IS NULL` filter would be
321
+ * flagged as an isolation violation). (#1600)
322
+ *
323
+ * @returns Array of global accounts
324
+ */
325
+ async findGlobal() {
326
+ return queryGlobal(this);
327
+ }
328
+ /**
329
+ * Find accounts for a tenant plus all global accounts.
330
+ *
331
+ * Fails closed if an active tenant context requests a different tenant's
332
+ * rows; the admin/system path keeps the cross-tenant capability. (#1600)
333
+ *
334
+ * @param tenantId - Tenant ID
335
+ * @returns Array of tenant's accounts and global accounts
336
+ */
337
+ async findWithGlobals(tenantId) {
338
+ return queryWithGlobals(this, tenantId, "Account.findWithGlobals");
339
+ }
340
+ };
341
+ var __defProp$1 = Object.defineProperty;
342
+ var __getOwnPropDesc$1 = Object.getOwnPropertyDescriptor;
343
+ var __decorateClass$1 = (decorators, target, key, kind) => {
344
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$1(target, key) : target;
345
+ for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
346
+ if (kind && result) __defProp$1(target, key, result);
347
+ return result;
348
+ };
349
+ var JournalEntry = class extends SmrtObject {
350
+ tenantId = null;
351
+ journalId = "";
352
+ accountId = "";
353
+ /**
354
+ * Debit amount (left side)
355
+ */
356
+ debit = 0;
357
+ /**
358
+ * Credit amount (right side)
359
+ */
360
+ credit = 0;
361
+ /**
362
+ * Currency code (e.g., "USD", "CAD", "EUR")
363
+ */
364
+ currency = "USD";
365
+ /**
366
+ * Exchange rate to base currency
367
+ */
368
+ exchangeRate = 1;
369
+ /**
370
+ * Line memo/description
371
+ */
372
+ memo = "";
373
+ /**
374
+ * Extensible metadata
375
+ */
376
+ metadata = {};
377
+ constructor(options = {}) {
378
+ super(options);
379
+ if (options.journalId !== void 0) this.journalId = options.journalId;
380
+ if (options.accountId !== void 0) this.accountId = options.accountId;
381
+ if (options.debit !== void 0) this.debit = options.debit;
382
+ if (options.credit !== void 0) this.credit = options.credit;
383
+ if (options.currency !== void 0) this.currency = options.currency;
384
+ if (options.exchangeRate !== void 0) this.exchangeRate = options.exchangeRate;
385
+ if (options.memo !== void 0) this.memo = options.memo;
386
+ if (options.metadata !== void 0) this.metadata = options.metadata;
387
+ }
388
+ /**
389
+ * Validate entry before save
390
+ */
391
+ async validateBeforeSave() {
392
+ await super.validateBeforeSave();
393
+ if (this.debit < 0) throw new Error("Debit amount cannot be negative");
394
+ if (this.credit < 0) throw new Error("Credit amount cannot be negative");
395
+ if (this.debit > 0 && this.credit > 0) throw new Error("Entry cannot have both debit and credit amounts");
396
+ if (this.debit === 0 && this.credit === 0) throw new Error("Entry must have either a debit or credit amount");
397
+ if (this.exchangeRate <= 0) throw new Error("Exchange rate must be positive");
398
+ }
399
+ /**
400
+ * Check if this is a debit entry
401
+ */
402
+ isDebit() {
403
+ return this.debit > 0;
404
+ }
405
+ /**
406
+ * Check if this is a credit entry
407
+ */
408
+ isCredit() {
409
+ return this.credit > 0;
410
+ }
411
+ /**
412
+ * Get the entry amount (positive value regardless of debit/credit)
413
+ */
414
+ getAmount() {
415
+ return this.debit > 0 ? this.debit : this.credit;
416
+ }
417
+ /**
418
+ * Get the amount in base currency
419
+ */
420
+ getBaseAmount() {
421
+ return this.getAmount() * this.exchangeRate;
422
+ }
423
+ /**
424
+ * Get the parent journal
425
+ */
426
+ async getJournal() {
427
+ if (!this.journalId) return null;
428
+ const { JournalCollection } = await Promise.resolve().then(() => Journals_exports);
429
+ return await (await JournalCollection.create(this.options)).get({ id: this.journalId });
430
+ }
431
+ /**
432
+ * Get the account
433
+ */
434
+ async getAccount() {
435
+ if (!this.accountId) return null;
436
+ const { AccountCollection } = await Promise.resolve().then(() => Accounts_exports);
437
+ return await (await AccountCollection.create(this.options)).get({ id: this.accountId });
438
+ }
439
+ /**
440
+ * Get a formatted description of this entry
441
+ */
442
+ async getDescription() {
443
+ const accountName = (await this.getAccount())?.name || "Unknown Account";
444
+ return `${this.isDebit() ? "DR" : "CR"} ${accountName}: $${this.getAmount().toFixed(2)}${this.memo ? ` - ${this.memo}` : ""}`;
445
+ }
446
+ };
447
+ __decorateClass$1([tenantId({ nullable: true })], JournalEntry.prototype, "tenantId", 2);
448
+ __decorateClass$1([foreignKey("Journal")], JournalEntry.prototype, "journalId", 2);
449
+ __decorateClass$1([foreignKey(Account)], JournalEntry.prototype, "accountId", 2);
450
+ JournalEntry = __decorateClass$1([TenantScoped({ mode: "optional" }), smrt({
451
+ api: { include: ["list", "get"] },
452
+ mcp: { include: ["list", "get"] },
453
+ cli: { skipApiCheck: true }
454
+ })], JournalEntry);
455
+ var JournalEntries_exports = /* @__PURE__ */ __exportAll({ JournalEntryCollection: () => JournalEntryCollection });
456
+ var JournalEntryCollection = class extends SmrtCollection {
457
+ static _itemClass = JournalEntry;
458
+ /**
459
+ * Find entries by journal
460
+ *
461
+ * @param journalId - Journal ID
462
+ * @returns Array of entries
463
+ */
464
+ async findByJournal(journalId) {
465
+ return await this.list({ where: { journalId } });
466
+ }
467
+ /**
468
+ * Find entries by account
469
+ *
470
+ * @param accountId - Account ID
471
+ * @returns Array of entries
472
+ */
473
+ async findByAccount(accountId) {
474
+ return await this.list({ where: { accountId } });
475
+ }
476
+ /**
477
+ * Get account balance
478
+ *
479
+ * For debit-normal accounts (Asset, Expense): balance = debits - credits
480
+ * For credit-normal accounts (Liability, Equity, Revenue): balance = credits - debits
481
+ *
482
+ * @param accountId - Account ID
483
+ * @param asOfDate - Optional date to calculate balance as of
484
+ * @returns Account balance
485
+ */
486
+ async getAccountBalance(accountId, asOfDate) {
487
+ const { JournalCollection } = await Promise.resolve().then(() => Journals_exports);
488
+ const journalCollection = await JournalCollection.create(this.options);
489
+ const { AccountCollection } = await Promise.resolve().then(() => Accounts_exports);
490
+ const account = await (await AccountCollection.create(this.options)).get({ id: accountId });
491
+ if (!account) throw new Error(`Account not found: ${accountId}`);
492
+ const allEntries = await this.findByAccount(accountId);
493
+ let totalDebits = 0;
494
+ let totalCredits = 0;
495
+ for (const entry of allEntries) {
496
+ const journal = await journalCollection.get({ id: entry.journalId });
497
+ if (!journal) continue;
498
+ if (!journal.isPosted()) continue;
499
+ if (asOfDate && journal.date > asOfDate) continue;
500
+ totalDebits += entry.debit;
501
+ totalCredits += entry.credit;
502
+ }
503
+ if (account.isDebitNormal()) return totalDebits - totalCredits;
504
+ else return totalCredits - totalDebits;
505
+ }
506
+ /**
507
+ * Get trial balance
508
+ *
509
+ * @param asOfDate - Optional date for trial balance
510
+ * @returns Array of trial balance rows
511
+ */
512
+ async getTrialBalance(asOfDate) {
513
+ const { AccountCollection } = await Promise.resolve().then(() => Accounts_exports);
514
+ const accounts = await (await AccountCollection.create(this.options)).findActive();
515
+ const rows = [];
516
+ for (const account of accounts) {
517
+ if (!account.id) continue;
518
+ const balance = await this.getAccountBalance(account.id, asOfDate);
519
+ if (Math.abs(balance) < .001) continue;
520
+ rows.push({
521
+ accountId: account.id,
522
+ accountNumber: account.number,
523
+ accountName: account.name,
524
+ accountType: account.type,
525
+ debitBalance: account.isDebitNormal() && balance > 0 ? balance : 0,
526
+ creditBalance: account.isCreditNormal() && balance > 0 ? balance : 0
527
+ });
528
+ }
529
+ rows.sort((a, b) => a.accountNumber.localeCompare(b.accountNumber));
530
+ return rows;
531
+ }
532
+ /**
533
+ * Get total debits and credits for a date range
534
+ *
535
+ * @param start - Start date
536
+ * @param end - End date
537
+ * @returns Object with totalDebits and totalCredits
538
+ */
539
+ async getTotalsForDateRange(start, end) {
540
+ const { JournalCollection } = await Promise.resolve().then(() => Journals_exports);
541
+ const journals = await (await JournalCollection.create(this.options)).findByDateRange(start, end);
542
+ let totalDebits = 0;
543
+ let totalCredits = 0;
544
+ for (const journal of journals) {
545
+ if (!journal.isPosted()) continue;
546
+ const entries = await this.findByJournal(journal.id);
547
+ for (const entry of entries) {
548
+ totalDebits += entry.debit;
549
+ totalCredits += entry.credit;
550
+ }
551
+ }
552
+ return {
553
+ totalDebits,
554
+ totalCredits
555
+ };
556
+ }
557
+ /**
558
+ * Get entries for multiple accounts
559
+ *
560
+ * @param accountIds - Array of account IDs
561
+ * @returns Array of entries
562
+ */
563
+ async findByAccounts(accountIds) {
564
+ if (accountIds.length === 0) return [];
565
+ return await this.list({ where: { accountId: accountIds } });
566
+ }
567
+ /**
568
+ * Get the running balance for an account (list of entries with running total)
569
+ *
570
+ * @param accountId - Account ID
571
+ * @returns Array of entries with running balance
572
+ */
573
+ async getAccountLedger(accountId) {
574
+ const { JournalCollection } = await Promise.resolve().then(() => Journals_exports);
575
+ const { AccountCollection } = await Promise.resolve().then(() => Accounts_exports);
576
+ const journalCollection = await JournalCollection.create(this.options);
577
+ const account = await (await AccountCollection.create(this.options)).get({ id: accountId });
578
+ if (!account) throw new Error(`Account not found: ${accountId}`);
579
+ const entries = await this.findByAccount(accountId);
580
+ const ledger = [];
581
+ let runningBalance = 0;
582
+ const entriesWithJournals = await Promise.all(entries.map(async (entry) => ({
583
+ entry,
584
+ journal: await journalCollection.get({ id: entry.journalId })
585
+ })));
586
+ entriesWithJournals.sort((a, b) => {
587
+ if (!a.journal || !b.journal) return 0;
588
+ return a.journal.date.getTime() - b.journal.date.getTime();
589
+ });
590
+ for (const { entry, journal } of entriesWithJournals) {
591
+ if (!journal?.isPosted()) continue;
592
+ if (account.isDebitNormal()) runningBalance += entry.debit - entry.credit;
593
+ else runningBalance += entry.credit - entry.debit;
594
+ ledger.push({
595
+ entry,
596
+ runningBalance
597
+ });
598
+ }
599
+ return ledger;
600
+ }
601
+ /**
602
+ * Find all journal entries belonging to a specific tenant
603
+ *
604
+ * @param tenantId - Tenant ID
605
+ * @returns Array of tenant's journal entries
606
+ */
607
+ async findByTenant(tenantId) {
608
+ return this.list({ where: { tenantId } });
609
+ }
610
+ /**
611
+ * Find all global journal entries (no tenant association).
612
+ *
613
+ * Routes through the shared tenant-global helper so it does not throw under
614
+ * an active tenant context. (#1600)
615
+ *
616
+ * @returns Array of global journal entries
617
+ */
618
+ async findGlobal() {
619
+ return queryGlobal(this);
620
+ }
621
+ /**
622
+ * Find journal entries for a tenant plus all global entries.
623
+ *
624
+ * Fails closed if an active tenant context requests a different tenant's
625
+ * rows; the admin/system path keeps the cross-tenant capability. (#1600)
626
+ *
627
+ * @param tenantId - Tenant ID
628
+ * @returns Array of tenant's entries and global entries
629
+ */
630
+ async findWithGlobals(tenantId) {
631
+ return queryWithGlobals(this, tenantId, "JournalEntry.findWithGlobals");
632
+ }
633
+ };
634
+ var __defProp = Object.defineProperty;
635
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
636
+ var __decorateClass = (decorators, target, key, kind) => {
637
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
638
+ for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
639
+ if (kind && result) __defProp(target, key, result);
640
+ return result;
641
+ };
642
+ var Journal = class extends SmrtObject {
643
+ tenantId = null;
644
+ /**
645
+ * Journal number (auto-generated sequence, e.g., "JNL-0001")
646
+ */
647
+ number = "";
648
+ /**
649
+ * Transaction date
650
+ */
651
+ date = /* @__PURE__ */ new Date();
652
+ /**
653
+ * Description of the financial event
654
+ */
655
+ description = "";
656
+ /**
657
+ * Source module that created this journal (e.g., "smrt-commerce", "manual")
658
+ */
659
+ sourceModule = "";
660
+ /**
661
+ * External reference (e.g., order ID, invoice number)
662
+ */
663
+ sourceRef = null;
664
+ /**
665
+ * Journal status: draft, posted, voided
666
+ */
667
+ status = "draft";
668
+ /**
669
+ * When the journal was posted (finalized)
670
+ */
671
+ postedAt = null;
672
+ /**
673
+ * When the journal was voided
674
+ */
675
+ voidedAt = null;
676
+ /**
677
+ * Reason for voiding (if voided)
678
+ */
679
+ voidReason = null;
680
+ /**
681
+ * Extensible metadata
682
+ */
683
+ metadata = {};
684
+ constructor(options = {}) {
685
+ super(options);
686
+ if (options.number !== void 0) this.number = options.number;
687
+ if (options.date !== void 0) this.date = options.date;
688
+ if (options.description !== void 0) this.description = options.description;
689
+ if (options.sourceModule !== void 0) this.sourceModule = options.sourceModule;
690
+ if (options.sourceRef !== void 0) this.sourceRef = options.sourceRef;
691
+ if (options.status !== void 0) this.status = options.status;
692
+ if (options.postedAt !== void 0) this.postedAt = options.postedAt;
693
+ if (options.voidedAt !== void 0) this.voidedAt = options.voidedAt;
694
+ if (options.voidReason !== void 0) this.voidReason = options.voidReason;
695
+ if (options.metadata !== void 0) this.metadata = options.metadata;
696
+ }
697
+ /**
698
+ * Check if journal is in draft status
699
+ */
700
+ isDraft() {
701
+ return this.status === "draft";
702
+ }
703
+ /**
704
+ * Check if journal has been posted
705
+ */
706
+ isPosted() {
707
+ return this.status === "posted";
708
+ }
709
+ /**
710
+ * Check if journal has been voided
711
+ */
712
+ isVoided() {
713
+ return this.status === "voided";
714
+ }
715
+ /**
716
+ * Check if journal can be modified
717
+ */
718
+ isEditable() {
719
+ return this.status === "draft";
720
+ }
721
+ /**
722
+ * Get all entries for this journal
723
+ */
724
+ async getEntries() {
725
+ if (!this.id) return [];
726
+ const { JournalEntryCollection } = await Promise.resolve().then(() => JournalEntries_exports);
727
+ return await (await JournalEntryCollection.create(this.options)).findByJournal(this.id);
728
+ }
729
+ /**
730
+ * Calculate total debits
731
+ */
732
+ async getTotalDebits() {
733
+ return (await this.getEntries()).reduce((sum, entry) => sum + entry.debit, 0);
734
+ }
735
+ /**
736
+ * Calculate total credits
737
+ */
738
+ async getTotalCredits() {
739
+ return (await this.getEntries()).reduce((sum, entry) => sum + entry.credit, 0);
740
+ }
741
+ /**
742
+ * Check if journal entries are balanced (debits = credits)
743
+ */
744
+ async isBalanced() {
745
+ const debits = await this.getTotalDebits();
746
+ const credits = await this.getTotalCredits();
747
+ return Math.abs(debits - credits) < BALANCE_EPSILON;
748
+ }
749
+ /**
750
+ * Add an entry to this journal (only if draft)
751
+ */
752
+ async addEntry(data) {
753
+ if (!this.id) throw new Error("Journal must be saved before adding entries");
754
+ if (!this.isEditable()) throw new Error("Cannot add entries to a posted or voided journal");
755
+ const { JournalEntryCollection } = await Promise.resolve().then(() => JournalEntries_exports);
756
+ await (await (await JournalEntryCollection.create(this.options)).create({
757
+ journalId: this.id,
758
+ accountId: data.accountId,
759
+ debit: data.debit || 0,
760
+ credit: data.credit || 0,
761
+ currency: data.currency || "USD",
762
+ exchangeRate: data.exchangeRate || 1,
763
+ memo: data.memo || ""
764
+ })).save();
765
+ }
766
+ /**
767
+ * Post the journal (finalize and make immutable)
768
+ */
769
+ async post() {
770
+ if (!this.isDraft()) throw new Error("Only draft journals can be posted");
771
+ if (!await this.isBalanced()) {
772
+ const debits = await this.getTotalDebits();
773
+ const credits = await this.getTotalCredits();
774
+ throw new Error(`Journal is not balanced. Debits: ${debits}, Credits: ${credits}`);
775
+ }
776
+ if ((await this.getEntries()).length === 0) throw new Error("Journal must have at least one entry");
777
+ this.status = "posted";
778
+ this.postedAt = /* @__PURE__ */ new Date();
779
+ await this.save();
780
+ }
781
+ /**
782
+ * Void the journal (mark as cancelled with reason)
783
+ */
784
+ async void(reason) {
785
+ if (this.isVoided()) throw new Error("Journal is already voided");
786
+ this.status = "voided";
787
+ this.voidedAt = /* @__PURE__ */ new Date();
788
+ this.voidReason = reason;
789
+ await this.save();
790
+ }
791
+ /**
792
+ * AI-powered: Generate a summary of this journal.
793
+ *
794
+ * Uses the `smrtLedgers.journal.summarize` prompt registered via
795
+ * `@happyvertical/smrt-prompts`, allowing tenant- or instance-level
796
+ * overrides of the template, model, and parameters at runtime.
797
+ *
798
+ * Only non-PII journal fields (number, date, description, status, balanced
799
+ * flag) plus aggregate totals and entry count are sent to the AI provider.
800
+ * Internal foreign-key fields (tenantId, sourceRef, individual entry
801
+ * account IDs) and the extensible `metadata` blob are intentionally
802
+ * excluded.
803
+ *
804
+ * @returns Generated summary text
805
+ */
806
+ async summarize() {
807
+ const entries = await this.getEntries();
808
+ const debits = await this.getTotalDebits();
809
+ const balanced = await this.isBalanced();
810
+ const db = this.options.db ?? this.options.persistence;
811
+ const resolvedPrompt = await resolvePrompt(smrtLedgersJournalSummarizePrompt.key, {
812
+ db,
813
+ tenantId: this.tenantId,
814
+ variables: {
815
+ journalNumber: this.number || "",
816
+ journalDate: this.date.toISOString().split("T")[0],
817
+ journalDescription: this.description || "",
818
+ journalStatus: this.status || "",
819
+ journalTotal: `$${debits.toFixed(2)}`,
820
+ entryCount: String(entries.length),
821
+ journalBalanced: balanced ? "Yes" : "No"
822
+ }
823
+ });
824
+ return (await (await this.getAiClient()).message(resolvedPrompt.text, promptMessageOptions(resolvedPrompt.ai))).trim();
825
+ }
826
+ };
827
+ __decorateClass([tenantId({ nullable: true })], Journal.prototype, "tenantId", 2);
828
+ Journal = __decorateClass([TenantScoped({ mode: "optional" }), smrt({
829
+ api: { include: [
830
+ "list",
831
+ "get",
832
+ "create"
833
+ ] },
834
+ mcp: { include: [
835
+ "list",
836
+ "get",
837
+ "create"
838
+ ] },
839
+ cli: { skipApiCheck: true }
840
+ })], Journal);
841
+ var Journals_exports = /* @__PURE__ */ __exportAll({ JournalCollection: () => JournalCollection });
842
+ var JournalCollection = class extends SmrtCollection {
843
+ static _itemClass = Journal;
844
+ /**
845
+ * Generate next journal number
846
+ *
847
+ * Uses timestamp and random component to avoid collisions
848
+ * in concurrent environments without relying on shared state.
849
+ */
850
+ generateJournalNumber() {
851
+ return `JNL-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`;
852
+ }
853
+ /**
854
+ * Find journal by number
855
+ *
856
+ * @param number - Journal number
857
+ * @returns Journal or null
858
+ */
859
+ async findByNumber(number) {
860
+ return (await this.list({
861
+ where: { number },
862
+ limit: 1
863
+ }))[0] || null;
864
+ }
865
+ /**
866
+ * Find journals by date range
867
+ *
868
+ * @param start - Start date
869
+ * @param end - End date
870
+ * @returns Array of journals
871
+ */
872
+ async findByDateRange(start, end) {
873
+ return await this.list({
874
+ where: {
875
+ "date >=": start.toISOString(),
876
+ "date <=": end.toISOString()
877
+ },
878
+ orderBy: "date ASC"
879
+ });
880
+ }
881
+ /**
882
+ * Find journals by source module
883
+ *
884
+ * @param sourceModule - Source module name
885
+ * @returns Array of journals
886
+ */
887
+ async findBySource(sourceModule) {
888
+ return await this.list({
889
+ where: { sourceModule },
890
+ orderBy: "date DESC"
891
+ });
892
+ }
893
+ /**
894
+ * Find journals by status
895
+ *
896
+ * @param status - Journal status
897
+ * @returns Array of journals
898
+ */
899
+ async findByStatus(status) {
900
+ return await this.list({
901
+ where: { status },
902
+ orderBy: "date DESC"
903
+ });
904
+ }
905
+ /**
906
+ * Find draft journals
907
+ *
908
+ * @returns Array of draft journals
909
+ */
910
+ async findDrafts() {
911
+ return await this.findByStatus("draft");
912
+ }
913
+ /**
914
+ * Find posted journals
915
+ *
916
+ * @returns Array of posted journals
917
+ */
918
+ async findPosted() {
919
+ return await this.findByStatus("posted");
920
+ }
921
+ /**
922
+ * Create a complete journal with entries
923
+ *
924
+ * @param data - Journal data with entries
925
+ * @returns Created journal
926
+ */
927
+ async createWithEntries(data) {
928
+ let totalDebits = 0;
929
+ let totalCredits = 0;
930
+ for (const entry of data.entries) {
931
+ totalDebits += entry.debit || 0;
932
+ totalCredits += entry.credit || 0;
933
+ }
934
+ if (Math.abs(totalDebits - totalCredits) >= .001) throw new Error(`Entries are not balanced. Debits: ${totalDebits}, Credits: ${totalCredits}`);
935
+ if (data.entries.length === 0) throw new Error("Journal must have at least one entry");
936
+ const journalNumber = await this.generateJournalNumber();
937
+ const journal = await this.create({
938
+ number: journalNumber,
939
+ date: data.date || /* @__PURE__ */ new Date(),
940
+ description: data.description,
941
+ sourceModule: data.sourceModule || "manual",
942
+ sourceRef: data.sourceRef || null,
943
+ metadata: data.metadata || {}
944
+ });
945
+ await journal.save();
946
+ for (const entryData of data.entries) await journal.addEntry(entryData);
947
+ return journal;
948
+ }
949
+ /**
950
+ * Post a journal by ID
951
+ *
952
+ * @param journalId - Journal ID
953
+ * @returns Posted journal
954
+ */
955
+ async post(journalId) {
956
+ const journal = await this.get({ id: journalId });
957
+ if (!journal) throw new Error(`Journal not found: ${journalId}`);
958
+ await journal.post();
959
+ return journal;
960
+ }
961
+ /**
962
+ * Void a journal by ID
963
+ *
964
+ * @param journalId - Journal ID
965
+ * @param reason - Reason for voiding
966
+ * @returns Voided journal
967
+ */
968
+ async void(journalId, reason) {
969
+ const journal = await this.get({ id: journalId });
970
+ if (!journal) throw new Error(`Journal not found: ${journalId}`);
971
+ await journal.void(reason);
972
+ return journal;
973
+ }
974
+ /**
975
+ * Find journals by source reference
976
+ *
977
+ * @param sourceRef - External reference
978
+ * @returns Array of journals
979
+ */
980
+ async findBySourceRef(sourceRef) {
981
+ return await this.list({
982
+ where: { sourceRef },
983
+ orderBy: "date DESC"
984
+ });
985
+ }
986
+ /**
987
+ * Get journals for a specific month
988
+ *
989
+ * @param year - Year
990
+ * @param month - Month (1-12)
991
+ * @returns Array of journals
992
+ */
993
+ async findByMonth(year, month) {
994
+ const start = new Date(year, month - 1, 1);
995
+ const end = new Date(year, month, 0, 23, 59, 59, 999);
996
+ return await this.findByDateRange(start, end);
997
+ }
998
+ /**
999
+ * Find all journals belonging to a specific tenant
1000
+ *
1001
+ * @param tenantId - Tenant ID
1002
+ * @returns Array of tenant's journals
1003
+ */
1004
+ async findByTenant(tenantId) {
1005
+ return this.list({ where: { tenantId } });
1006
+ }
1007
+ /**
1008
+ * Find all global journals (no tenant association).
1009
+ *
1010
+ * Routes through the shared tenant-global helper so it does not throw under
1011
+ * an active tenant context. (#1600)
1012
+ *
1013
+ * @returns Array of global journals
1014
+ */
1015
+ async findGlobal() {
1016
+ return queryGlobal(this);
1017
+ }
1018
+ /**
1019
+ * Find journals for a tenant plus all global journals.
1020
+ *
1021
+ * Fails closed if an active tenant context requests a different tenant's
1022
+ * rows; the admin/system path keeps the cross-tenant capability. (#1600)
1023
+ *
1024
+ * @param tenantId - Tenant ID
1025
+ * @returns Array of tenant's journals and global journals
1026
+ */
1027
+ async findWithGlobals(tenantId) {
1028
+ return queryWithGlobals(this, tenantId, "Journal.findWithGlobals");
1029
+ }
1030
+ };
1031
+ var LEDGER_ACCOUNTS_TABLE = "ledger_accounts";
1032
+ var LEGACY_ACCOUNTS_TABLE = "accounts";
1033
+ var LEGACY_LEDGER_SIGNATURE = ["number", "type"];
1034
+ var STI_DISCRIMINATOR = "_meta_type";
1035
+ var MESSAGING_MARKERS = ["provider_type", "channel_type"];
1036
+ var LedgerAccountsTableMoveError = class extends Error {
1037
+ constructor(message) {
1038
+ super(message);
1039
+ this.name = "LedgerAccountsTableMoveError";
1040
+ }
1041
+ };
1042
+ function quote(identifier) {
1043
+ return `"${identifier.replace(/"/g, "\"\"")}"`;
1044
+ }
1045
+ function timeout(value, fallback) {
1046
+ const milliseconds = value ?? fallback;
1047
+ if (!Number.isInteger(milliseconds) || milliseconds < 0) throw new LedgerAccountsTableMoveError("Migration timeout must be a non-negative integer");
1048
+ return `${milliseconds}ms`;
1049
+ }
1050
+ function assertPostgres(db) {
1051
+ const withConfig = db;
1052
+ if (detectEngine(db.url || withConfig.config?.url || "", withConfig.type || withConfig.config?.type) !== "postgres") throw new LedgerAccountsTableMoveError("The ledger accounts table move supports PostgreSQL only. For a SQLite database whose `accounts` table holds only ledger accounts, run `ALTER TABLE accounts RENAME TO ledger_accounts` before `db:migrate`; see the smrt-ledgers README.");
1053
+ }
1054
+ async function readLegacyShape(db) {
1055
+ const schema = await db.getTableSchema?.(LEGACY_ACCOUNTS_TABLE);
1056
+ if (!schema) return null;
1057
+ const columns = new Set(Object.keys(schema.columns));
1058
+ if (!LEGACY_LEDGER_SIGNATURE.every((column) => columns.has(column))) return null;
1059
+ return {
1060
+ columns,
1061
+ hasDiscriminator: columns.has(STI_DISCRIMINATOR)
1062
+ };
1063
+ }
1064
+ function ledgerRowPredicate(shape) {
1065
+ return shape.hasDiscriminator ? `(${quote(STI_DISCRIMINATOR)} IS NULL OR ${quote(STI_DISCRIMINATOR)} = '')` : "TRUE";
1066
+ }
1067
+ async function count(db, where) {
1068
+ const result = await db.query(`SELECT COUNT(*) AS n FROM ${quote(LEGACY_ACCOUNTS_TABLE)} WHERE ${where}`);
1069
+ return Number(result.rows[0].n);
1070
+ }
1071
+ async function classify(db, shape) {
1072
+ const ledger = ledgerRowPredicate(shape);
1073
+ const pending = await count(db, ledger);
1074
+ const messagingRows = shape.hasDiscriminator ? await count(db, `NOT ${ledger}`) : 0;
1075
+ if (shape.hasDiscriminator) {
1076
+ const ledgerLooking = await count(db, `NOT ${ledger} AND COALESCE(${quote("number")}, '') <> ''`);
1077
+ const markers = MESSAGING_MARKERS.filter((column) => shape.columns.has(column));
1078
+ const messagingLooking = markers.length === 0 ? 0 : await count(db, `${ledger} AND (${markers.map((column) => `COALESCE(${quote(column)}, '') <> ''`).join(" OR ")})`);
1079
+ if (ledgerLooking > 0 || messagingLooking > 0) throw new LedgerAccountsTableMoveError(`Refusing to move ledger accounts: ${ledgerLooking} messaging row(s) carry a ledger account number and ${messagingLooking} ledger row(s) carry a messaging provider or channel in "${LEGACY_ACCOUNTS_TABLE}". Resolve their ownership by hand, then rerun.`);
1080
+ }
1081
+ return {
1082
+ pending,
1083
+ messagingRows
1084
+ };
1085
+ }
1086
+ function registeredReferenceColumns() {
1087
+ const ledger = /* @__PURE__ */ new Set();
1088
+ const accounts = /* @__PURE__ */ new Set();
1089
+ const schemas = ObjectRegistry.getAllSchemasAsDefinitions();
1090
+ for (const [tableName, schema] of Object.entries(schemas)) for (const [columnName, column] of Object.entries(schema.columns ?? {})) {
1091
+ const target = column.foreignKey?.table;
1092
+ if (target === "ledger_accounts") ledger.add(`${tableName}.${columnName}`);
1093
+ else if (target === "accounts") accounts.add(`${tableName}.${columnName}`);
1094
+ }
1095
+ return {
1096
+ ledger,
1097
+ accounts
1098
+ };
1099
+ }
1100
+ function classifyForeignKeys(inbound, references) {
1101
+ const disposition = {
1102
+ composite: [],
1103
+ undeclared: [],
1104
+ detach: [],
1105
+ keep: []
1106
+ };
1107
+ for (const fk of inbound) {
1108
+ const key = `${fk.table}.${fk.column}`;
1109
+ if (fk.arity > 1) disposition.composite.push(fk);
1110
+ else if (references.ledger.has(key)) disposition.detach.push(fk);
1111
+ else if (fk.table === "accounts" || references.accounts.has(key)) disposition.keep.push(fk);
1112
+ else disposition.undeclared.push(fk);
1113
+ }
1114
+ return disposition;
1115
+ }
1116
+ function foreignKeyRefusal(disposition) {
1117
+ if (disposition.composite.length > 0) return `Composite foreign key(s) ${disposition.composite.map((fk) => `${fk.constraint} on ${fk.table} (${fk.arity} columns)`).join(", ")} reference "${LEGACY_ACCOUNTS_TABLE}"; no model can declare one, so the move cannot carry it. Nothing was moved. Drop it, or replace it with a single-column reference, then rerun.`;
1118
+ if (disposition.undeclared.length > 0) return `Foreign key(s) ${disposition.undeclared.map((fk) => `${fk.table}.${fk.column}`).join(", ")} reference "${LEGACY_ACCOUNTS_TABLE}" but no registered model declares them; nothing was moved. Run the move from the application whose models declare them, or retarget each to "${LEDGER_ACCOUNTS_TABLE}" (or drop it) by hand, then rerun.`;
1119
+ }
1120
+ function copySelectList(columns, targetTypes, legacyTypes) {
1121
+ return columns.map((column) => {
1122
+ const to = targetTypes[column];
1123
+ return sameType(legacyTypes[column], to) ? quote(column) : `CAST(CAST(${quote(column)} AS TEXT) AS ${targetType(to)})`;
1124
+ }).join(", ");
1125
+ }
1126
+ async function legacyForeignKeys(db) {
1127
+ return (await db.query(`SELECT con.conname AS constraint_name,
1128
+ rel.relname AS table_name,
1129
+ att.attname AS column_name,
1130
+ array_length(con.conkey, 1) AS arity
1131
+ FROM pg_constraint con
1132
+ JOIN pg_class rel ON rel.oid = con.conrelid
1133
+ JOIN pg_attribute att
1134
+ ON att.attrelid = con.conrelid AND att.attnum = con.conkey[1]
1135
+ WHERE con.contype = 'f'
1136
+ AND con.confrelid = to_regclass(?)
1137
+ ORDER BY rel.relname, con.conname`, quote(LEGACY_ACCOUNTS_TABLE))).rows.map((row) => ({
1138
+ constraint: row.constraint_name,
1139
+ table: row.table_name,
1140
+ column: row.column_name,
1141
+ arity: Number(row.arity)
1142
+ }));
1143
+ }
1144
+ async function planLedgerAccountsTableMove(db) {
1145
+ const shape = await readLegacyShape(db);
1146
+ if (!shape) return {
1147
+ legacyTable: false,
1148
+ pending: 0,
1149
+ messagingRows: 0
1150
+ };
1151
+ return {
1152
+ legacyTable: true,
1153
+ ...await classify(db, shape)
1154
+ };
1155
+ }
1156
+ async function migrateLedgerAccountsTable(db, options = {}) {
1157
+ assertPostgres(db);
1158
+ if (!db.transaction) throw new LedgerAccountsTableMoveError("The ledger accounts table move requires a transaction-capable PostgreSQL adapter");
1159
+ const noop = (remainingLegacyRows = 0) => ({
1160
+ ran: false,
1161
+ moved: 0,
1162
+ remainingLegacyRows,
1163
+ detachedForeignKeys: []
1164
+ });
1165
+ const shape = await readLegacyShape(db);
1166
+ if (!shape) return noop();
1167
+ const target = await db.getTableSchema?.(LEDGER_ACCOUNTS_TABLE);
1168
+ if (!target) throw new LedgerAccountsTableMoveError(`"${LEDGER_ACCOUNTS_TABLE}" does not exist; run db:migrate before moving ledger accounts`);
1169
+ const legacy = await db.getTableSchema?.(LEGACY_ACCOUNTS_TABLE);
1170
+ const copyColumns = Object.keys(target.columns).filter((column) => shape.columns.has(column));
1171
+ const references = registeredReferenceColumns();
1172
+ await new BackfillTracker({ db }).initialize();
1173
+ const backfillName = options.backfillName ?? "@happyvertical/smrt-ledgers:ledger-accounts-table:v1";
1174
+ return db.transaction(async (tx) => {
1175
+ BackfillTracker.inheritInitialization(tx, db);
1176
+ const transactionTracker = new BackfillTracker({ db: tx });
1177
+ await tx.query(`SET LOCAL lock_timeout = '${timeout(options.lockTimeout, 3e4)}'`);
1178
+ await tx.query(`SET LOCAL statement_timeout = '${timeout(options.statementTimeout, 6e4)}'`);
1179
+ await tx.query(`LOCK TABLE ${quote(LEGACY_ACCOUNTS_TABLE)}, ${quote(LEDGER_ACCOUNTS_TABLE)} IN ACCESS EXCLUSIVE MODE`);
1180
+ const { pending, messagingRows } = await classify(tx, shape);
1181
+ if (await transactionTracker.isApplied(backfillName)) {
1182
+ if (pending > 0) throw new LedgerAccountsTableMoveError(`The ledger accounts table move is recorded as applied but "${LEGACY_ACCOUNTS_TABLE}" still holds ${pending} ledger row(s); refusing inconsistent state`);
1183
+ return noop(messagingRows);
1184
+ }
1185
+ const ledger = ledgerRowPredicate(shape);
1186
+ const clash = await tx.query(`SELECT COUNT(*) AS n FROM ${quote(LEGACY_ACCOUNTS_TABLE)} legacy
1187
+ WHERE ${ledger}
1188
+ AND EXISTS (SELECT 1 FROM ${quote(LEDGER_ACCOUNTS_TABLE)} moved
1189
+ WHERE CAST(moved.id AS TEXT) = CAST(legacy.id AS TEXT))`);
1190
+ if (Number(clash.rows[0].n) > 0) throw new LedgerAccountsTableMoveError(`"${LEDGER_ACCOUNTS_TABLE}" already holds ids of ledger rows still in "${LEGACY_ACCOUNTS_TABLE}"; refusing to overwrite`);
1191
+ const disposition = classifyForeignKeys(await legacyForeignKeys(tx), references);
1192
+ const refusal = foreignKeyRefusal(disposition);
1193
+ if (refusal) throw new LedgerAccountsTableMoveError(refusal);
1194
+ for (const fk of disposition.keep) {
1195
+ const survivor = fk.table === "accounts" ? ` AND NOT ${ledger}` : "";
1196
+ const pointing = await tx.query(`SELECT COUNT(*) AS n FROM ${quote(fk.table)}
1197
+ WHERE ${quote(fk.column)} IN
1198
+ (SELECT id FROM ${quote(LEGACY_ACCOUNTS_TABLE)} WHERE ${ledger})${survivor}`);
1199
+ if (Number(pointing.rows[0].n) > 0) throw new LedgerAccountsTableMoveError(`${fk.table}.${fk.column} references ledger accounts in "${LEGACY_ACCOUNTS_TABLE}" but is not a ledger reference; nothing was moved. Resolve those rows by hand, then rerun.`);
1200
+ }
1201
+ const selectList = copySelectList(copyColumns, columnTypes(target), columnTypes(legacy));
1202
+ await tx.query(`INSERT INTO ${quote(LEDGER_ACCOUNTS_TABLE)} (${copyColumns.map(quote).join(", ")})
1203
+ SELECT ${selectList} FROM ${quote(LEGACY_ACCOUNTS_TABLE)} WHERE ${ledger}`);
1204
+ const detached = [];
1205
+ for (const foreignKey of disposition.detach) {
1206
+ await tx.query(`ALTER TABLE ${quote(foreignKey.table)} DROP CONSTRAINT ${quote(foreignKey.constraint)}`);
1207
+ detached.push(`${foreignKey.table}.${foreignKey.column}`);
1208
+ }
1209
+ await tx.query(`DELETE FROM ${quote(LEGACY_ACCOUNTS_TABLE)} WHERE ${ledger}`);
1210
+ await transactionTracker.recordApplied(backfillName, {
1211
+ description: "Moved ledger accounts from the shared accounts table to ledger_accounts (#3098).",
1212
+ packageName: options.packageName ?? "@happyvertical/smrt-ledgers"
1213
+ });
1214
+ return {
1215
+ ran: true,
1216
+ moved: pending,
1217
+ remainingLegacyRows: messagingRows,
1218
+ detachedForeignKeys: detached
1219
+ };
1220
+ });
1221
+ }
1222
+ var SQL_TYPE = /^[A-Za-z][A-Za-z0-9 _]*(\(\d+(,\s*\d+)?\))?(\[\])?$/;
1223
+ function columnTypes(schema) {
1224
+ return Object.fromEntries(Object.entries(schema?.columns ?? {}).map(([name, column]) => [name, column.type]));
1225
+ }
1226
+ function sameType(from, to) {
1227
+ return from !== void 0 && to !== void 0 && from.trim().toLowerCase() === to.trim().toLowerCase();
1228
+ }
1229
+ function targetType(declared) {
1230
+ const type = declared?.trim();
1231
+ if (!type || !SQL_TYPE.test(type)) throw new LedgerAccountsTableMoveError(`Cannot copy into "${LEDGER_ACCOUNTS_TABLE}": unsupported live column type ${JSON.stringify(type)}`);
1232
+ return type;
1233
+ }
1234
+ //#endregion
1235
+ export { migrateLedgerAccountsTable, Accounts_exports as n, planLedgerAccountsTableMove, JournalEntries_exports as t };