@classytic/ledger 0.4.2 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +227 -189
  2. package/dist/constants/index.d.mts +1 -1
  3. package/dist/constants/index.mjs +2 -3
  4. package/dist/country/index.d.mts +1 -1
  5. package/dist/{journals-BfwnCFam.mjs → currencies-CsuBGfgs.mjs} +80 -1
  6. package/dist/{date-lock.plugin-DL6pe24p.mjs → date-lock.plugin-B2Jy0ukX.mjs} +61 -10
  7. package/dist/errors-BmRjW38t.mjs +33 -0
  8. package/dist/exports/index.d.mts +1 -1
  9. package/dist/exports/index.mjs +1 -1
  10. package/dist/{fiscal-close-B2_7WMTe.mjs → fiscal-close-Dk3yRT9i.mjs} +14 -4
  11. package/dist/{index-CxZqRaOU.d.mts → index-GmfEFxVn.d.mts} +1 -1
  12. package/dist/index.d.mts +525 -344
  13. package/dist/index.mjs +1814 -170
  14. package/dist/{journals-DTipb_rz.d.mts → journals-C50E9mpo.d.mts} +1 -1
  15. package/dist/plugins/index.d.mts +1 -1
  16. package/dist/plugins/index.mjs +1 -1
  17. package/dist/reports/index.d.mts +1 -1
  18. package/dist/reports/index.mjs +1 -1
  19. package/dist/{trial-balance-DcQ0xj_4.d.mts → trial-balance-BZ7yOOFD.d.mts} +16 -4
  20. package/package.json +1 -11
  21. package/dist/currencies-W8kQAkm0.mjs +0 -80
  22. package/dist/engine-scgOvxHJ.d.mts +0 -130
  23. package/dist/errors-B_dyYZc_.mjs +0 -26
  24. package/dist/journal-entry.schema-JqrfbvB4.d.mts +0 -103
  25. package/dist/logger-UbTdBb1x.d.mts +0 -14
  26. package/dist/reconciliation.repository-D-D_ITL-.d.mts +0 -135
  27. package/dist/reconciliation.repository-fPwFKvrk.mjs +0 -542
  28. package/dist/reconciliation.schema-BA1lPv4t.mjs +0 -666
  29. package/dist/repositories/index.d.mts +0 -2
  30. package/dist/repositories/index.mjs +0 -2
  31. package/dist/schemas/index.d.mts +0 -71
  32. package/dist/schemas/index.mjs +0 -2
  33. package/dist/tenant-guard-r17Se3Bb.mjs +0 -13
  34. /package/dist/{categories-DWogBUgQ.mjs → categories-BkKdv16V.mjs} +0 -0
  35. /package/dist/{core-8Xfnpn6g.d.mts → core-BkGjuVZj.d.mts} +0 -0
  36. /package/dist/{exports-DoGQQtMQ.mjs → exports-BP-0Ni5W.mjs} +0 -0
  37. /package/dist/{idempotency.plugin-zU-GKJ0-.d.mts → idempotency.plugin-CK7LHnBn.d.mts} +0 -0
  38. /package/dist/{index-J-XIbXH-.d.mts → index-D1ZjgVxn.d.mts} +0 -0
package/dist/index.d.mts CHANGED
@@ -1,18 +1,157 @@
1
- import { _ as TaxMetadata, a as Cents, c as DateRange, d as JournalType, f as MainType, g as TaxDetail, h as StatementType, i as CategoryKey, l as EntryState, m as ObjectId, n as CashFlowCategory, o as Currency, p as NormalBalance, s as DateOption, t as AccountType, u as JournalItem, v as TotalAccountOp } from "./core-8Xfnpn6g.mjs";
2
- import { S as isValidCategory, a as getJournalTypeCodes, b as isBalanceSheet, c as CURRENCIES, d as isValidCurrency, f as CATEGORIES, i as getJournalType, l as getCurrency, n as JOURNAL_TYPES, o as isValidJournalType, p as CATEGORY_KEYS, r as getCustomJournalTypes, s as registerJournalType, t as JOURNAL_CODES, u as getMinorUnit, x as isIncomeStatement, y as getNormalBalance } from "./journals-DTipb_rz.mjs";
3
- import { a as TaxReportLine, i as TaxCodesByRegion, n as CountryPackInput, o as TaxReportTemplate, r as TaxCode, s as defineCountryPack, t as CountryPack } from "./index-CxZqRaOU.mjs";
4
- import { _ as PopulatedJournalEntry, a as exportToCsv, h as FlatJournalRow, i as quickbooksFieldMap, m as ExportFieldMap, p as ExportField, r as universalFieldMap, t as flattenJournalEntries } from "./index-J-XIbXH-.mjs";
1
+ import { _ as TaxMetadata, a as Cents, c as DateRange, d as JournalType, f as MainType, g as TaxDetail, h as StatementType, i as CategoryKey, l as EntryState, m as ObjectId, n as CashFlowCategory, o as Currency, p as NormalBalance, s as DateOption, t as AccountType, u as JournalItem, v as TotalAccountOp } from "./core-BkGjuVZj.mjs";
2
+ import { S as isValidCategory, a as getJournalTypeCodes, b as isBalanceSheet, c as CURRENCIES, d as isValidCurrency, f as CATEGORIES, i as getJournalType, l as getCurrency, n as JOURNAL_TYPES, o as isValidJournalType, p as CATEGORY_KEYS, r as getCustomJournalTypes, s as registerJournalType, t as JOURNAL_CODES, u as getMinorUnit, x as isIncomeStatement, y as getNormalBalance } from "./journals-C50E9mpo.mjs";
3
+ import { a as TaxReportLine, i as TaxCodesByRegion, n as CountryPackInput, o as TaxReportTemplate, r as TaxCode, s as defineCountryPack, t as CountryPack } from "./index-GmfEFxVn.mjs";
4
+ import { _ as PopulatedJournalEntry, a as exportToCsv, h as FlatJournalRow, i as quickbooksFieldMap, m as ExportFieldMap, p as ExportField, r as universalFieldMap, t as flattenJournalEntries } from "./index-D1ZjgVxn.mjs";
5
5
  import { Money, abs, add, allocate, equals, format, formatPlain, fromDecimal, isNegative, isPositive, isValid, isZero, max, min, multiply, negate, parseCents, percentage, round, splitTaxExclusive, splitTaxInclusive, subtract, toDecimal } from "./money.mjs";
6
- import { n as defaultLogger, t as Logger } from "./logger-UbTdBb1x.mjs";
7
- import { a as MultiCurrencyConfig, c as StrictnessConfig, i as ModelNames, n as AuditConfig, o as MultiTenantConfig, r as JournalSchemaOptions, s as SchemaOptions, t as AccountingEngineConfig } from "./engine-scgOvxHJ.mjs";
8
- import { a as BulkCreateInput, c as PostOptions, d as ReverseOptions, f as ReverseResult, i as AccountRepository, l as ReconcileParams, m as SeedResult, n as wireJournalEntryMethods, o as BulkCreateResult, p as SeedOptions, r as wireAccountMethods, s as JournalEntryRepository, t as wireReconciliationMethods, u as ReconciliationRepository } from "./reconciliation.repository-D-D_ITL-.mjs";
9
- import { n as createFiscalPeriodSchema, r as createAccountSchema, t as createJournalEntrySchema } from "./journal-entry.schema-JqrfbvB4.mjs";
10
- import { c as dateLockPlugin, i as fiscalLockPlugin, n as idempotencyPlugin, o as doubleEntryPlugin } from "./idempotency.plugin-zU-GKJ0-.mjs";
11
- import { $ as AgedBucketConfig, A as BudgetVsActualReport, B as IncomeStatementReport, C as DimensionBreakdownReport, D as generateCashFlow, F as BalanceSheetReport, G as TaxReport, H as ReportAccount, I as CashFlowReport, J as TrialBalanceRow, K as TaxReturnSummary, L as CashFlowSection, M as generateBudgetVsActual, O as BudgetVsActualOptions, P as generateBalanceSheet, Q as AgedBalanceRow, R as GeneralLedgerAccount, S as DimensionBreakdownParams, T as generateDimensionBreakdown, U as ReportCategory, V as LedgerEntry, W as ReportGroup, X as AgedBalanceParams, Y as AgedBalanceOptions, Z as AgedBalanceReport, a as RevaluationReport, b as reopenFiscalPeriod, c as RevaluationRate, d as computeRevaluation, et as DEFAULT_BUCKETS, h as generateGeneralLedger, i as RevaluationParams, j as BudgetVsActualRow, k as BudgetVsActualParams, l as RevaluationResult, n as generateTrialBalance, o as generateRevaluation, p as generateIncomeStatement, q as TrialBalanceReport, r as RevaluationOptions, s as AccountForeignBalance, tt as generateAgedBalance, u as buildRevaluationEntry, w as DimensionBreakdownRow, x as DimensionBreakdownOptions, y as closeFiscalPeriod, z as GeneralLedgerReport } from "./trial-balance-DcQ0xj_4.mjs";
12
- import * as mongoose$1 from "mongoose";
6
+ import { $ as AgedBucketConfig, A as BudgetVsActualReport, B as IncomeStatementReport, C as DimensionBreakdownReport, D as generateCashFlow, F as BalanceSheetReport, G as TaxReport, H as ReportAccount, I as CashFlowReport, J as TrialBalanceRow, K as TaxReturnSummary, L as CashFlowSection, M as generateBudgetVsActual, O as BudgetVsActualOptions, P as generateBalanceSheet, Q as AgedBalanceRow, R as GeneralLedgerAccount, S as DimensionBreakdownParams, T as generateDimensionBreakdown, U as ReportCategory, V as LedgerEntry, W as ReportGroup, X as AgedBalanceParams, Y as AgedBalanceOptions, Z as AgedBalanceReport, a as RevaluationReport, b as reopenFiscalPeriod, c as RevaluationRate, d as computeRevaluation, et as DEFAULT_BUCKETS, h as generateGeneralLedger, i as RevaluationParams, j as BudgetVsActualRow, k as BudgetVsActualParams, l as RevaluationResult, n as generateTrialBalance, nt as Logger, o as generateRevaluation, p as generateIncomeStatement, q as TrialBalanceReport, r as RevaluationOptions, rt as defaultLogger, s as AccountForeignBalance, tt as generateAgedBalance, u as buildRevaluationEntry, w as DimensionBreakdownRow, x as DimensionBreakdownOptions, y as closeFiscalPeriod, z as GeneralLedgerReport } from "./trial-balance-BZ7yOOFD.mjs";
7
+ import { c as dateLockPlugin, i as fiscalLockPlugin, n as idempotencyPlugin, o as doubleEntryPlugin } from "./idempotency.plugin-CK7LHnBn.mjs";
13
8
  import { ClientSession, Connection, Model } from "mongoose";
14
9
  import { PaginationConfig, PluginType, Repository } from "@classytic/mongokit";
15
10
 
11
+ //#region src/types/engine.d.ts
12
+ /** Mongokit plugins to install per repository (composes with engine built-ins). */
13
+ interface LedgerRepositoryPlugins {
14
+ account?: PluginType[];
15
+ journalEntry?: PluginType[];
16
+ fiscalPeriod?: PluginType[];
17
+ budget?: PluginType[];
18
+ reconciliation?: PluginType[];
19
+ }
20
+ /** Pagination caps per repository. Omit a key to use mongokit defaults. */
21
+ interface LedgerPaginationConfig {
22
+ account?: PaginationConfig;
23
+ journalEntry?: PaginationConfig;
24
+ fiscalPeriod?: PaginationConfig;
25
+ budget?: PaginationConfig;
26
+ reconciliation?: PaginationConfig;
27
+ }
28
+ /** Multi-tenant configuration */
29
+ interface MultiTenantConfig {
30
+ /** Field name for the organization reference (e.g., 'business', 'organization', 'company') */
31
+ orgField: string;
32
+ /** Mongoose model name the org field references (e.g., 'Business', 'Organization') */
33
+ orgRef: string;
34
+ }
35
+ /** Options passed to schema factory functions */
36
+ interface SchemaOptions {
37
+ /** Add recommended indexes (default: true) */
38
+ indexes?: boolean;
39
+ /** Extra Mongoose schema fields to merge in */
40
+ extraFields?: Record<string, unknown>;
41
+ /** Extra indexes to add */
42
+ extraIndexes?: Array<{
43
+ fields: Record<string, 1 | -1>;
44
+ options?: Record<string, unknown>;
45
+ }>;
46
+ }
47
+ /** Journal entry schema-specific options */
48
+ interface JournalSchemaOptions extends SchemaOptions {
49
+ /** Auto-generate reference numbers (default: true) */
50
+ autoReference?: boolean;
51
+ /** Enable text search index on reference + label (default: true) */
52
+ textSearch?: boolean;
53
+ /** Extra Mongoose schema fields to merge into the JournalItem subdocument */
54
+ extraItemFields?: Record<string, unknown>;
55
+ }
56
+ /** Audit trail configuration */
57
+ interface AuditConfig {
58
+ /** Track actor (user) who performs each operation (post, reverse, approve) */
59
+ trackActor?: boolean;
60
+ }
61
+ /** Strictness rules for the ledger */
62
+ interface StrictnessConfig {
63
+ /** If true, unpost() is disabled — correction only via reverse() (immutable ledger) */
64
+ immutable?: boolean;
65
+ /** If true, actorId is required on post/reverse/unpost operations */
66
+ requireActor?: boolean;
67
+ /** If true, entries must have approvedBy/approvedAt set before posting */
68
+ requireApproval?: boolean;
69
+ }
70
+ /**
71
+ * Multi-currency configuration.
72
+ * When enabled, adds currency and exchange rate fields to journal items
73
+ * and a currency field to accounts. Allows recording transactions in
74
+ * foreign currencies while maintaining a base (functional) currency.
75
+ *
76
+ * @example
77
+ * ```typescript
78
+ * const engine = createAccountingEngine({
79
+ * country: canadaPack,
80
+ * currency: 'CAD', // base/functional currency
81
+ * multiCurrency: {
82
+ * enabled: true,
83
+ * currencies: ['USD', 'GBP', 'BDT'], // allowed foreign currencies
84
+ * },
85
+ * });
86
+ * ```
87
+ */
88
+ interface MultiCurrencyConfig {
89
+ /** Enable multi-currency fields on schemas */
90
+ enabled: boolean;
91
+ /** Allowed foreign currency codes. If omitted, any ISO 4217 code is accepted. */
92
+ currencies?: readonly string[];
93
+ }
94
+ /**
95
+ * Override default model names. Useful when you want to avoid collisions
96
+ * with existing models or use custom naming conventions.
97
+ */
98
+ interface ModelNames {
99
+ account?: string;
100
+ journalEntry?: string;
101
+ fiscalPeriod?: string;
102
+ budget?: string;
103
+ reconciliation?: string;
104
+ }
105
+ /** Main engine configuration */
106
+ interface AccountingEngineConfig {
107
+ /**
108
+ * Mongoose connection. **Required** — the engine owns all models and
109
+ * creates them on this connection.
110
+ */
111
+ mongoose: Connection;
112
+ /** Override default model names (e.g. 'Account' → 'GLAccount') */
113
+ modelNames?: ModelNames;
114
+ /** Extra fields / indexes per model */
115
+ schemaOptions?: {
116
+ account?: SchemaOptions;
117
+ journalEntry?: JournalSchemaOptions;
118
+ fiscalPeriod?: SchemaOptions;
119
+ budget?: SchemaOptions;
120
+ reconciliation?: SchemaOptions;
121
+ };
122
+ /** Country pack providing account types, tax codes, and templates */
123
+ country: CountryPack;
124
+ /** Default ISO 4217 currency code — the functional/base currency (e.g., 'CAD', 'BDT') */
125
+ currency: string;
126
+ /** Multi-tenant configuration. Omit for single-tenant apps. */
127
+ multiTenant?: MultiTenantConfig;
128
+ /** Multi-currency support. Omit for single-currency apps. */
129
+ multiCurrency?: MultiCurrencyConfig;
130
+ /** Fiscal year start month (1-12, default: 1 = January) */
131
+ fiscalYearStartMonth?: number;
132
+ /**
133
+ * The retained earnings account code (e.g. '3600' CA, '3310' BD).
134
+ * Overrides the country pack value. See CountryPack.retainedEarningsAccountCode.
135
+ */
136
+ retainedEarningsAccountCode?: string;
137
+ /** Display code for the "Previous Years Retained Earnings" line. Overrides country pack. */
138
+ retainedEarningsDisplayCode?: string;
139
+ /** Display code for current year net income line. Overrides country pack. */
140
+ currentYearEarningsCode?: string;
141
+ /** Logger instance. Defaults to console-based logger. */
142
+ logger?: Logger;
143
+ /** Audit trail configuration */
144
+ audit?: AuditConfig;
145
+ /** Enable built-in idempotency key field on journal entries */
146
+ idempotency?: boolean;
147
+ /** Strictness rules for the ledger */
148
+ strictness?: StrictnessConfig;
149
+ /** Mongokit plugins to install per repository. */
150
+ plugins?: LedgerRepositoryPlugins;
151
+ /** Pagination caps per repository. */
152
+ pagination?: LedgerPaginationConfig;
153
+ }
154
+ //#endregion
16
155
  //#region src/models/factory.d.ts
17
156
  interface LedgerModels {
18
157
  Account: Model<unknown>;
@@ -38,25 +177,100 @@ declare function resolveModelNames(overrides?: ModelNames): ResolvedModelNames;
38
177
  */
39
178
  declare function createModels(connection: Connection, config: AccountingEngineConfig): LedgerModels;
40
179
  //#endregion
41
- //#region src/repositories/factory.d.ts
42
- interface LedgerRepositoryPlugins {
43
- account?: PluginType[];
44
- journalEntry?: PluginType[];
45
- fiscalPeriod?: PluginType[];
46
- budget?: PluginType[];
47
- reconciliation?: PluginType[];
180
+ //#region src/types/repositories.d.ts
181
+ interface PostOptions {
182
+ session?: ClientSession | null;
183
+ /** Actor performing this operation (required when strictness.requireActor is enabled) */
184
+ actorId?: unknown;
185
+ }
186
+ interface ReverseOptions extends PostOptions {
187
+ /** Date for the reversal entry (defaults to now) */
188
+ reversalDate?: Date;
189
+ }
190
+ interface SeedOptions {
191
+ session?: ClientSession | null;
192
+ }
193
+ interface SeedResult {
194
+ created: number;
195
+ skipped: number;
196
+ }
197
+ interface BulkCreateInput {
198
+ accountTypeCode?: string;
199
+ accountNumber?: string;
200
+ name?: string;
201
+ active?: boolean;
202
+ isCashAccount?: boolean;
203
+ }
204
+ interface BulkCreateResult {
205
+ summary: {
206
+ total: number;
207
+ created: number;
208
+ skipped: number;
209
+ errors: number;
210
+ };
211
+ created: Array<Record<string, unknown>>;
212
+ skipped: Array<Record<string, unknown>>;
213
+ errors: Array<Record<string, unknown>>;
214
+ }
215
+ interface ReverseResult {
216
+ original: Record<string, unknown>;
217
+ reversal: Record<string, unknown>;
218
+ }
219
+ interface ReconcileParams {
220
+ accountId: unknown;
221
+ journalEntryIds: unknown[];
222
+ organizationId?: unknown;
223
+ note?: string;
224
+ session?: ClientSession;
48
225
  }
49
226
  /**
50
- * Pagination config per repository. Defaults to `{ maxLimit: 1000 }` for accounts
51
- * (typical chart of accounts size), 100 for everything else.
227
+ * Journal Entry Repository extends mongokit Repository with accounting domain methods.
228
+ *
229
+ * Inherits ALL Repository<TDoc> methods: create, getById, getAll, update,
230
+ * delete, count, exists, distinct, aggregate, withTransaction, etc.
52
231
  */
53
- interface LedgerPaginationConfig {
54
- account?: PaginationConfig;
55
- journalEntry?: PaginationConfig;
56
- fiscalPeriod?: PaginationConfig;
57
- budget?: PaginationConfig;
58
- reconciliation?: PaginationConfig;
232
+ interface JournalEntryRepository<TDoc = unknown> extends Repository<TDoc> {
233
+ /** Post an entry (draft → posted). Validates items, balance, and accounts. */
234
+ post(id: unknown, orgId?: unknown, options?: PostOptions): Promise<Record<string, unknown>>;
235
+ /** Unpost an entry (posted → draft). Resets state for re-editing. */
236
+ unpost(id: unknown, orgId?: unknown, options?: PostOptions): Promise<Record<string, unknown>>;
237
+ /** Archive a draft entry (draft → archived). Preserves audit trail. */
238
+ archive(id: unknown, orgId?: unknown, options?: PostOptions): Promise<Record<string, unknown>>;
239
+ /** Duplicate an entry as a new draft. Copies items, type, and label. */
240
+ duplicate(id: unknown, orgId?: unknown, options?: PostOptions): Promise<Record<string, unknown>>;
241
+ /** Reverse a posted entry. Creates mirror entry with flipped debits/credits. */
242
+ reverse(id: unknown, orgId?: unknown, options?: ReverseOptions): Promise<ReverseResult>;
243
+ }
244
+ /**
245
+ * Account Repository — extends mongokit Repository with seed and bulk operations.
246
+ */
247
+ interface AccountRepository<TDoc = unknown> extends Repository<TDoc> {
248
+ /** Seed standard posting accounts for an org from the country pack. */
249
+ seedAccounts(orgId: unknown, options?: SeedOptions): Promise<SeedResult>;
250
+ /** Bulk create accounts with validation and skip-if-exists logic. */
251
+ bulkCreate(accounts: BulkCreateInput[], orgId: unknown): Promise<BulkCreateResult>;
252
+ }
253
+ /**
254
+ * Reconciliation Repository — extends mongokit Repository with bank reconciliation methods.
255
+ */
256
+ interface ReconciliationRepository<TDoc = unknown> extends Repository<TDoc> {
257
+ /** Reconcile journal entries for a specific account. */
258
+ reconcile(params: ReconcileParams): Promise<Record<string, unknown>>;
259
+ /** Remove a reconciliation record. */
260
+ unreconcile(params: {
261
+ reconciliationId: unknown;
262
+ organizationId?: unknown;
263
+ }): Promise<{
264
+ success: boolean;
265
+ }>;
266
+ /** Get unreconciled journal entries for an account. */
267
+ getUnreconciled(params: {
268
+ accountId: unknown;
269
+ organizationId?: unknown;
270
+ }): Promise<Record<string, unknown>[]>;
59
271
  }
272
+ //#endregion
273
+ //#region src/repositories/factory.d.ts
60
274
  interface LedgerRepositories {
61
275
  accounts: AccountRepository<unknown>;
62
276
  journalEntries: JournalEntryRepository<unknown>;
@@ -75,6 +289,247 @@ interface LedgerRepositories {
75
289
  */
76
290
  declare function createRepositories(models: LedgerModels, config: AccountingEngineConfig, plugins?: LedgerRepositoryPlugins, pagination?: LedgerPaginationConfig): LedgerRepositories;
77
291
  //#endregion
292
+ //#region src/semantic/introspect.d.ts
293
+ interface AccountSummary {
294
+ /** Mongoose _id */
295
+ readonly id: string;
296
+ /** Account type code from country pack (e.g. '1001') */
297
+ readonly code: string;
298
+ /** Display name from country pack */
299
+ readonly name: string;
300
+ /** Statement category (Balance Sheet-Asset, Income Statement-Expense, etc.) */
301
+ readonly category: string;
302
+ /** Normal balance (debit or credit) */
303
+ readonly normalBalance: 'debit' | 'credit';
304
+ /** Parent group code if nested */
305
+ readonly parentCode: string | null;
306
+ /** Is this a posting account (not a group/total)? */
307
+ readonly isPosting: boolean;
308
+ /** True if the Account document is active */
309
+ readonly active: boolean;
310
+ /** Organization id (multi-tenant only) */
311
+ readonly organizationId?: string;
312
+ }
313
+ interface ReportDescriptor {
314
+ /** Programmatic name (e.g. 'trialBalance') */
315
+ readonly name: string;
316
+ /** Human-readable title */
317
+ readonly title: string;
318
+ /** Short description of what it returns */
319
+ readonly description: string;
320
+ /** List of parameter names and whether required */
321
+ readonly params: ReadonlyArray<{
322
+ readonly name: string;
323
+ readonly required: boolean;
324
+ readonly description: string;
325
+ }>;
326
+ }
327
+ interface FiscalPeriodSummary {
328
+ readonly id: string;
329
+ readonly name: string;
330
+ readonly startDate: Date;
331
+ readonly endDate: Date;
332
+ readonly closed: boolean;
333
+ readonly closedAt?: Date;
334
+ readonly organizationId?: string;
335
+ }
336
+ interface IntrospectAPI {
337
+ /**
338
+ * List all accounts for an organization (or all if single-tenant).
339
+ * Returns structured summaries suitable for MCP tool responses.
340
+ */
341
+ accounts(organizationId?: unknown, session?: ClientSession | null): Promise<AccountSummary[]>;
342
+ /**
343
+ * List all journal types — built-in (15) plus any custom types
344
+ * registered via `registerJournalType()`.
345
+ */
346
+ journalTypes(): ReadonlyArray<JournalType>;
347
+ /**
348
+ * List all available reports with their parameter schemas.
349
+ * Agents use this to discover what analytics they can run.
350
+ */
351
+ reports(): ReadonlyArray<ReportDescriptor>;
352
+ /**
353
+ * List tax codes — all of them, or filtered by region.
354
+ */
355
+ taxCodes(region?: string): ReadonlyArray<TaxCode>;
356
+ /**
357
+ * List fiscal periods for an organization.
358
+ */
359
+ fiscalPeriods(organizationId?: unknown, session?: ClientSession | null): Promise<FiscalPeriodSummary[]>;
360
+ /**
361
+ * A one-shot snapshot of everything an agent needs to start working:
362
+ * accounts, journal types, reports, tax codes, fiscal periods.
363
+ */
364
+ catalog(organizationId?: unknown): Promise<{
365
+ accounts: AccountSummary[];
366
+ journalTypes: ReadonlyArray<JournalType>;
367
+ reports: ReadonlyArray<ReportDescriptor>;
368
+ taxCodes: ReadonlyArray<TaxCode>;
369
+ fiscalPeriods: FiscalPeriodSummary[];
370
+ }>;
371
+ }
372
+ //#endregion
373
+ //#region src/semantic/record.d.ts
374
+ /**
375
+ * A lightweight shape matching mongokit's UserContext — the actor that
376
+ * performs an operation. Passed through to repository hooks as `context.user`,
377
+ * where the audit-trail plugin picks up `user._id` automatically.
378
+ */
379
+ interface ActorContext {
380
+ readonly _id?: string;
381
+ readonly id?: string;
382
+ readonly roles?: string | readonly string[];
383
+ readonly [key: string]: unknown;
384
+ }
385
+ type AccountCode = string;
386
+ /** Integer-cents amount. */
387
+ type Cents$1 = number;
388
+ interface TaxInput {
389
+ /** Tax code from the country pack (e.g. 'HST', 'GST', 'VAT') */
390
+ readonly code: string;
391
+ /**
392
+ * Account type code where the tax amount posts.
393
+ * For sales: the tax-payable account (e.g. '2300' HST Collected).
394
+ * For expenses: the tax-recoverable (ITC) account (e.g. '2400' HST Paid).
395
+ */
396
+ readonly account: AccountCode;
397
+ /**
398
+ * If true, `amount` is tax-inclusive and will be split into base + tax.
399
+ * If false (default), `amount` is the tax-exclusive base and tax is added.
400
+ */
401
+ readonly inclusive?: boolean;
402
+ }
403
+ /**
404
+ * Options passed to every record.* operation. Matches mongokit's
405
+ * RepositoryContext shape so audit/observability plugins pick them up
406
+ * with zero glue code.
407
+ *
408
+ * - `user` → surfaced on context.user (audit-trail reads user._id)
409
+ * - `session` → surfaced on context.session (participates in transactions)
410
+ * - `idempotencyKey` → sets journalEntry.idempotencyKey (requires idempotency: true in engine config)
411
+ * - any extra field → spread into context for custom plugins
412
+ */
413
+ interface RecordOptions {
414
+ readonly session?: ClientSession | null;
415
+ /** The actor performing the operation — flows to hook `context.user`. */
416
+ readonly user?: ActorContext;
417
+ /** Short-hand: sets createdBy/postedBy on the journal entry directly. */
418
+ readonly actorId?: string;
419
+ /** Deterministic idempotency key (for at-most-once posting). */
420
+ readonly idempotencyKey?: string;
421
+ /** Extra context fields — picked up by custom plugins via context[key]. */
422
+ readonly [key: string]: unknown;
423
+ }
424
+ interface RecordSaleInput {
425
+ /** Transaction date */
426
+ readonly date: Date;
427
+ /** Tax-exclusive sale amount in integer cents (unless `tax.inclusive` is true) */
428
+ readonly amount: Cents$1;
429
+ /** Account that receives the money — either Cash or Accounts Receivable */
430
+ readonly receivableAccount: AccountCode;
431
+ /** Revenue account */
432
+ readonly revenueAccount: AccountCode;
433
+ /** Tax info — optional */
434
+ readonly tax?: TaxInput;
435
+ /** Free-text label / memo */
436
+ readonly label?: string;
437
+ /** Optional reference number override (otherwise auto-generated) */
438
+ readonly reference?: string;
439
+ /** Extra fields to attach to journal items (e.g. departmentId, projectId) */
440
+ readonly dimensions?: Record<string, unknown>;
441
+ /** Journal type (defaults to 'SALES') */
442
+ readonly journalType?: string;
443
+ }
444
+ interface RecordExpenseInput {
445
+ readonly date: Date;
446
+ /** Tax-exclusive expense amount in cents (unless `tax.inclusive` is true) */
447
+ readonly amount: Cents$1;
448
+ /** Expense category account (e.g. '6010' Rent) */
449
+ readonly expenseAccount: AccountCode;
450
+ /** Where the money came from — either Cash or Accounts Payable */
451
+ readonly paidFromAccount: AccountCode;
452
+ /** Tax info (recoverable input tax credit) */
453
+ readonly tax?: TaxInput;
454
+ readonly label?: string;
455
+ readonly reference?: string;
456
+ readonly dimensions?: Record<string, unknown>;
457
+ readonly journalType?: string;
458
+ }
459
+ interface RecordTransferInput {
460
+ readonly date: Date;
461
+ readonly amount: Cents$1;
462
+ readonly fromAccount: AccountCode;
463
+ readonly toAccount: AccountCode;
464
+ readonly label?: string;
465
+ readonly reference?: string;
466
+ readonly dimensions?: Record<string, unknown>;
467
+ readonly journalType?: string;
468
+ }
469
+ interface RecordPaymentInput {
470
+ readonly date: Date;
471
+ readonly amount: Cents$1;
472
+ /** Customer receivable account being cleared (e.g. '1200' AR) */
473
+ readonly fromReceivableAccount: AccountCode;
474
+ /** Cash account receiving the payment (e.g. '1001' Cash) */
475
+ readonly toCashAccount: AccountCode;
476
+ readonly label?: string;
477
+ readonly reference?: string;
478
+ readonly dimensions?: Record<string, unknown>;
479
+ readonly journalType?: string;
480
+ }
481
+ interface RecordAdjustmentLine {
482
+ /** Account type code */
483
+ readonly account: AccountCode;
484
+ readonly debit?: Cents$1;
485
+ readonly credit?: Cents$1;
486
+ readonly label?: string;
487
+ }
488
+ interface RecordAdjustmentInput {
489
+ readonly date: Date;
490
+ readonly lines: readonly RecordAdjustmentLine[];
491
+ readonly label?: string;
492
+ readonly reference?: string;
493
+ readonly dimensions?: Record<string, unknown>;
494
+ readonly journalType?: string;
495
+ }
496
+ interface RecordAPI {
497
+ /**
498
+ * Record a sale. Debits cash/AR, credits revenue, splits tax if provided.
499
+ *
500
+ * @example
501
+ * ```typescript
502
+ * await engine.record.sale(orgId, {
503
+ * date: new Date('2025-04-01'),
504
+ * amount: 10000, // $100.00 base
505
+ * receivableAccount: '1001', // Cash
506
+ * revenueAccount: '4010', // Service Revenue
507
+ * tax: { code: 'HST', account: '2300' }, // 13% HST Collected
508
+ * label: 'Invoice #INV-001',
509
+ * });
510
+ * ```
511
+ */
512
+ sale(organizationId: unknown, input: RecordSaleInput, options?: RecordOptions): Promise<unknown>;
513
+ /**
514
+ * Record an expense. Debits expense, credits cash/AP, splits input tax credit if provided.
515
+ */
516
+ expense(organizationId: unknown, input: RecordExpenseInput, options?: RecordOptions): Promise<unknown>;
517
+ /**
518
+ * Record a transfer between two balance-sheet accounts (e.g. cash → bank).
519
+ */
520
+ transfer(organizationId: unknown, input: RecordTransferInput, options?: RecordOptions): Promise<unknown>;
521
+ /**
522
+ * Record a customer payment (AR → Cash). Clears the receivable.
523
+ */
524
+ payment(organizationId: unknown, input: RecordPaymentInput, options?: RecordOptions): Promise<unknown>;
525
+ /**
526
+ * Record a general adjustment with arbitrary line items.
527
+ * Use for corrections, accruals, depreciation — anything that doesn't fit
528
+ * the other verbs. Amounts must balance (debits = credits).
529
+ */
530
+ adjustment(organizationId: unknown, input: RecordAdjustmentInput, options?: RecordOptions): Promise<unknown>;
531
+ }
532
+ //#endregion
78
533
  //#region src/engine.d.ts
79
534
  declare class AccountingEngine {
80
535
  readonly config: AccountingEngineConfig;
@@ -104,26 +559,15 @@ declare class AccountingEngine {
104
559
  readonly isValid: typeof isValid;
105
560
  readonly parseCents: typeof parseCents;
106
561
  };
107
- private _models?;
108
- private _repositories?;
562
+ readonly models: LedgerModels;
563
+ readonly repositories: LedgerRepositories;
564
+ readonly record: RecordAPI;
565
+ readonly introspect: IntrospectAPI;
109
566
  private _reports?;
110
- constructor(config: AccountingEngineConfig, plugins?: LedgerRepositoryPlugins, pagination?: LedgerPaginationConfig);
567
+ constructor(config: AccountingEngineConfig);
111
568
  /**
112
- * Auto-created Mongoose models. Requires `mongoose` in config.
113
- *
114
- * @throws if `mongoose` was not provided in config
115
- */
116
- get models(): LedgerModels;
117
- /**
118
- * Auto-wired repositories with plugins + domain methods (post, reverse, etc.).
119
- * Requires `mongoose` in config.
120
- *
121
- * @throws if `mongoose` was not provided in config
122
- */
123
- get repositories(): LedgerRepositories;
124
- /**
125
- * Pre-built reports bound to auto-created models. Requires `mongoose` in config.
126
- * For custom models, use `engine.createReports({ Account, JournalEntry, Budget })`.
569
+ * Pre-built reports bound to the engine's owned models.
570
+ * Lazy-initialized on first access.
127
571
  */
128
572
  get reports(): {
129
573
  trialBalance: (params: {
@@ -200,246 +644,6 @@ declare class AccountingEngine {
200
644
  generateEntry?: boolean;
201
645
  }) => Promise<RevaluationReport>;
202
646
  };
203
- createAccountSchema(options?: SchemaOptions): mongoose$1.Schema<any, Model<any, any, any, any, any, any, any>, {}, {}, {}, {}, {
204
- timestamps: true;
205
- }, {
206
- [x: number]: any;
207
- [x: string]: any;
208
- } & mongoose$1.DefaultTimestampProps, mongoose$1.Document<unknown, {}, {
209
- [x: number]: any;
210
- [x: string]: any;
211
- } & mongoose$1.DefaultTimestampProps, {
212
- id: string;
213
- }, Omit<mongoose$1.DefaultSchemaOptions, "timestamps"> & {
214
- timestamps: true;
215
- }> & Omit<{
216
- [x: number]: any;
217
- [x: string]: any;
218
- } & mongoose$1.DefaultTimestampProps & {
219
- _id: mongoose$1.Types.ObjectId;
220
- } & {
221
- __v: number;
222
- }, "id"> & {
223
- id: string;
224
- }, unknown, {
225
- [x: number]: any;
226
- [x: string]: any;
227
- createdAt: NativeDate;
228
- updatedAt: NativeDate;
229
- } & {
230
- _id: mongoose$1.Types.ObjectId;
231
- } & {
232
- __v: number;
233
- }>;
234
- createJournalEntrySchema(accountModelName: string, options?: JournalSchemaOptions): mongoose$1.Schema<any, Model<any, any, any, any, any, any, any>, {}, {}, {}, {}, {
235
- timestamps: true;
236
- }, {
237
- [x: number]: any;
238
- [x: string]: any;
239
- } & mongoose$1.DefaultTimestampProps, mongoose$1.Document<unknown, {}, {
240
- [x: number]: any;
241
- [x: string]: any;
242
- } & mongoose$1.DefaultTimestampProps, {
243
- id: string;
244
- }, Omit<mongoose$1.DefaultSchemaOptions, "timestamps"> & {
245
- timestamps: true;
246
- }> & Omit<{
247
- [x: number]: any;
248
- [x: string]: any;
249
- } & mongoose$1.DefaultTimestampProps & {
250
- _id: mongoose$1.Types.ObjectId;
251
- } & {
252
- __v: number;
253
- }, "id"> & {
254
- id: string;
255
- }, unknown, {
256
- [x: number]: any;
257
- [x: string]: any;
258
- createdAt: NativeDate;
259
- updatedAt: NativeDate;
260
- } & {
261
- _id: mongoose$1.Types.ObjectId;
262
- } & {
263
- __v: number;
264
- }>;
265
- createFiscalPeriodSchema(options?: SchemaOptions): mongoose$1.Schema<any, Model<any, any, any, any, any, any, any>, {}, {}, {}, {}, {
266
- timestamps: true;
267
- }, {
268
- [x: number]: any;
269
- [x: string]: any;
270
- } & mongoose$1.DefaultTimestampProps, mongoose$1.Document<unknown, {}, {
271
- [x: number]: any;
272
- [x: string]: any;
273
- } & mongoose$1.DefaultTimestampProps, {
274
- id: string;
275
- }, Omit<mongoose$1.DefaultSchemaOptions, "timestamps"> & {
276
- timestamps: true;
277
- }> & Omit<{
278
- [x: number]: any;
279
- [x: string]: any;
280
- } & mongoose$1.DefaultTimestampProps & {
281
- _id: mongoose$1.Types.ObjectId;
282
- } & {
283
- __v: number;
284
- }, "id"> & {
285
- id: string;
286
- }, unknown, {
287
- [x: number]: any;
288
- [x: string]: any;
289
- createdAt: NativeDate;
290
- updatedAt: NativeDate;
291
- } & {
292
- _id: mongoose$1.Types.ObjectId;
293
- } & {
294
- __v: number;
295
- }>;
296
- createBudgetSchema(options?: SchemaOptions): mongoose$1.Schema<any, Model<any, any, any, any, any, any, any>, {}, {}, {}, {}, {
297
- timestamps: true;
298
- }, {
299
- [x: number]: any;
300
- [x: string]: any;
301
- } & mongoose$1.DefaultTimestampProps, mongoose$1.Document<unknown, {}, {
302
- [x: number]: any;
303
- [x: string]: any;
304
- } & mongoose$1.DefaultTimestampProps, {
305
- id: string;
306
- }, Omit<mongoose$1.DefaultSchemaOptions, "timestamps"> & {
307
- timestamps: true;
308
- }> & Omit<{
309
- [x: number]: any;
310
- [x: string]: any;
311
- } & mongoose$1.DefaultTimestampProps & {
312
- _id: mongoose$1.Types.ObjectId;
313
- } & {
314
- __v: number;
315
- }, "id"> & {
316
- id: string;
317
- }, unknown, {
318
- [x: number]: any;
319
- [x: string]: any;
320
- createdAt: NativeDate;
321
- updatedAt: NativeDate;
322
- } & {
323
- _id: mongoose$1.Types.ObjectId;
324
- } & {
325
- __v: number;
326
- }>;
327
- createReconciliationSchema(accountModelName: string, journalEntryModelName: string, options?: SchemaOptions): mongoose$1.Schema<any, Model<any, any, any, any, any, any, any>, {}, {}, {}, {}, {
328
- timestamps: true;
329
- }, {
330
- [x: number]: any;
331
- [x: string]: any;
332
- } & mongoose$1.DefaultTimestampProps, mongoose$1.Document<unknown, {}, {
333
- [x: number]: any;
334
- [x: string]: any;
335
- } & mongoose$1.DefaultTimestampProps, {
336
- id: string;
337
- }, Omit<mongoose$1.DefaultSchemaOptions, "timestamps"> & {
338
- timestamps: true;
339
- }> & Omit<{
340
- [x: number]: any;
341
- [x: string]: any;
342
- } & mongoose$1.DefaultTimestampProps & {
343
- _id: mongoose$1.Types.ObjectId;
344
- } & {
345
- __v: number;
346
- }, "id"> & {
347
- id: string;
348
- }, unknown, {
349
- [x: number]: any;
350
- [x: string]: any;
351
- createdAt: NativeDate;
352
- updatedAt: NativeDate;
353
- } & {
354
- _id: mongoose$1.Types.ObjectId;
355
- } & {
356
- __v: number;
357
- }>;
358
- /**
359
- * Build a reports object bound to the given models. Use this when you
360
- * need custom/external models. Prefer `engine.reports` when the engine
361
- * owns the models (via `mongoose` in config).
362
- */
363
- createReports(models: {
364
- Account: Model<unknown>;
365
- JournalEntry: Model<unknown>;
366
- Budget?: Model<unknown>;
367
- }): {
368
- trialBalance: (params: {
369
- organizationId?: unknown;
370
- dateOption: "month" | "quarter" | "year" | "custom";
371
- dateValue: unknown;
372
- accountId?: string;
373
- filters?: Record<string, unknown>;
374
- }) => Promise<TrialBalanceReport>;
375
- balanceSheet: (params: {
376
- organizationId?: unknown;
377
- dateOption: "month" | "quarter" | "year" | "custom";
378
- dateValue: unknown;
379
- businessName?: string;
380
- filters?: Record<string, unknown>;
381
- }) => Promise<BalanceSheetReport>;
382
- incomeStatement: (params: {
383
- organizationId?: unknown;
384
- dateOption: "month" | "quarter" | "year" | "custom";
385
- dateValue: unknown;
386
- businessName?: string;
387
- filters?: Record<string, unknown>;
388
- }) => Promise<IncomeStatementReport>;
389
- generalLedger: (params: {
390
- organizationId?: unknown;
391
- dateOption: "month" | "quarter" | "year" | "custom";
392
- dateValue: unknown;
393
- accountId?: string;
394
- filters?: Record<string, unknown>;
395
- }) => Promise<GeneralLedgerReport>;
396
- cashFlow: (params: {
397
- organizationId?: unknown;
398
- dateOption: "month" | "quarter" | "year" | "custom";
399
- dateValue: unknown;
400
- businessName?: string;
401
- filters?: Record<string, unknown>;
402
- }) => Promise<CashFlowReport>;
403
- agedBalance: (params: {
404
- organizationId?: unknown;
405
- asOfDate?: Date;
406
- type: "receivable" | "payable";
407
- accountIds?: unknown[];
408
- dueDateField?: string;
409
- contactField?: string;
410
- buckets?: Array<{
411
- label: string;
412
- minDays: number;
413
- maxDays: number;
414
- }>;
415
- }) => Promise<AgedBalanceReport>;
416
- dimensionBreakdown: (params: {
417
- organizationId?: unknown;
418
- dateOption: "month" | "quarter" | "year" | "custom";
419
- dateValue: unknown;
420
- dimension: string;
421
- accountCategory?: string;
422
- filters?: Record<string, unknown>;
423
- }) => Promise<DimensionBreakdownReport>;
424
- budgetVsActual: (params: {
425
- organizationId?: unknown;
426
- dateOption: "month" | "quarter" | "year" | "custom";
427
- dateValue: unknown;
428
- accountIds?: unknown[];
429
- filters?: Record<string, unknown>;
430
- }) => Promise<BudgetVsActualReport>;
431
- revaluation: (params: {
432
- organizationId?: unknown;
433
- asOfDate: Date;
434
- rates: Array<{
435
- currency: string;
436
- rate: number;
437
- }>;
438
- unrealizedGainLossAccountId: unknown;
439
- generateEntry?: boolean;
440
- }) => Promise<RevaluationReport>;
441
- };
442
- private _buildReports;
443
647
  /** Get all posting account types (accounts you can post transactions to) */
444
648
  getPostingAccountTypes(): readonly AccountType[];
445
649
  /** Validate an account type code */
@@ -448,57 +652,9 @@ declare class AccountingEngine {
448
652
  getAccountType(code: string): AccountType | undefined;
449
653
  /** Get tax codes for a region */
450
654
  getTaxCodesForRegion(region: string): TaxCode[];
451
- /**
452
- * Create a fully-configured journal entry repository with secure plugin wiring.
453
- * This is the **recommended** way to set up journal entry repositories.
454
- *
455
- * Includes:
456
- * - Double-entry plugin with account existence + tenant integrity validation
457
- * - Fiscal lock plugin (when FiscalPeriodModel is provided)
458
- * - post(), unpost(), reverse(), and duplicate() domain methods
459
- *
460
- * @param createRepository - The `createRepository` function from @classytic/mongokit
461
- * @param models.JournalEntryModel - Mongoose model for journal entries
462
- * @param models.AccountModel - Mongoose model for accounts (required for secure posted-create validation)
463
- * @param models.FiscalPeriodModel - Mongoose model for fiscal periods (optional, enables fiscal lock)
464
- * @param additionalPlugins - Extra plugins to include (e.g. timestampPlugin)
465
- * @returns A wired repository with post(), unpost(), reverse(), duplicate(), and all plugins configured
466
- */
467
- createJournalEntryRepository<TDoc = unknown>(createRepository: (model: Model<TDoc>, plugins: PluginType[]) => Repository<TDoc>, models: {
468
- JournalEntryModel: Model<TDoc>;
469
- AccountModel: Model<unknown>;
470
- FiscalPeriodModel?: Model<unknown>;
471
- }, additionalPlugins?: PluginType[]): JournalEntryRepository<TDoc>;
472
- /**
473
- * Wire post/reverse domain methods onto a mongokit Repository
474
- * for journal entries. The repository must already be created via
475
- * `createRepository(Model, plugins)` from @classytic/mongokit.
476
- *
477
- * **Note:** Prefer `createJournalEntryRepository()` which guarantees
478
- * secure plugin wiring. This method only adds domain methods and does
479
- * not validate plugin configuration.
480
- *
481
- * @param repository - An existing mongokit Repository instance
482
- * @param JournalEntryModel - The Mongoose model for journal entries
483
- * @returns The same repository, now with `.post()` and `.reverse()`
484
- */
485
- wireJournalEntryRepository<TDoc = unknown>(repository: Repository<TDoc>, JournalEntryModel: Model<unknown>): JournalEntryRepository<TDoc>;
486
- /**
487
- * Wire seedAccounts/bulkCreate and posting-account validation onto a
488
- * mongokit Repository for accounts. The repository must already be
489
- * created via `createRepository(Model, plugins)` from @classytic/mongokit.
490
- *
491
- * @param repository - An existing mongokit Repository instance
492
- * @param AccountModel - The Mongoose model for accounts
493
- * @returns The same repository, now with `.seedAccounts()` and `.bulkCreate()`
494
- */
495
- wireAccountRepository<TDoc = unknown>(repository: Repository<TDoc>, AccountModel: Model<unknown>): AccountRepository<TDoc>;
496
- /**
497
- * Wire reconcile/unreconcile/getUnreconciled methods onto a mongokit Repository.
498
- */
499
- wireReconciliationRepository<TDoc = unknown>(repository: Repository<TDoc>, ReconciliationModel: Model<unknown>, JournalEntryModel: Model<unknown>): ReconciliationRepository<TDoc>;
655
+ private _buildReports;
500
656
  }
501
- declare function createAccountingEngine(config: AccountingEngineConfig, plugins?: LedgerRepositoryPlugins, pagination?: LedgerPaginationConfig): AccountingEngine;
657
+ declare function createAccountingEngine(config: AccountingEngineConfig): AccountingEngine;
502
658
  //#endregion
503
659
  //#region src/utils/account-helpers.d.ts
504
660
  /**
@@ -594,21 +750,46 @@ declare function buildDimensionIndexes(dimensions: DimensionDefinition[], orgFie
594
750
  //#region src/utils/errors.d.ts
595
751
  /**
596
752
  * Typed error for the accounting package.
597
- * Carries HTTP status + machine-readable code.
598
- * Replaces all ad-hoc `(error as ...).status = N` patterns.
753
+ * Carries HTTP status + machine-readable code + structured field errors.
754
+ *
755
+ * The `fields` array lets AI agents and API clients pinpoint exactly
756
+ * what failed in a multi-field validation:
757
+ *
758
+ * throw Errors.validationWithFields('Journal entry invalid', [
759
+ * { path: 'journalItems.2.account', issue: 'account does not exist', value: '...' },
760
+ * { path: 'journalItems', issue: 'debits must equal credits', value: { debit: 500, credit: 450 } },
761
+ * ]);
599
762
  */
763
+ /** A single field-level validation error. */
764
+ interface FieldError {
765
+ /** Dot-notation path to the invalid field (e.g. `journalItems.2.account`) */
766
+ readonly path: string;
767
+ /** Human-readable description of what's wrong */
768
+ readonly issue: string;
769
+ /** The offending value (optional — omit for sensitive data) */
770
+ readonly value?: unknown;
771
+ }
600
772
  declare class AccountingError extends Error {
601
773
  readonly status: number;
602
774
  readonly code: string;
603
- constructor(message: string, status?: number, code?: string);
775
+ readonly fields?: ReadonlyArray<FieldError>;
776
+ constructor(message: string, status?: number, code?: string, fields?: ReadonlyArray<FieldError>);
777
+ /** Serialize to a plain object for API responses and logs. */
778
+ toJSON(): {
779
+ name: string;
780
+ message: string;
781
+ status: number;
782
+ code: string;
783
+ fields?: ReadonlyArray<FieldError>;
784
+ };
604
785
  }
605
- /** Convenience factory functions */
786
+ /** Convenience factory functions. */
606
787
  declare const Errors: {
607
- readonly validation: (msg: string) => AccountingError;
608
- readonly notFound: (msg: string) => AccountingError;
609
- readonly conflict: (msg: string) => AccountingError;
610
- readonly immutable: (msg: string) => AccountingError;
611
- readonly fiscal: (msg: string) => AccountingError;
788
+ readonly validation: (msg: string, fields?: ReadonlyArray<FieldError>) => AccountingError;
789
+ readonly notFound: (msg: string, fields?: ReadonlyArray<FieldError>) => AccountingError;
790
+ readonly conflict: (msg: string, fields?: ReadonlyArray<FieldError>) => AccountingError;
791
+ readonly immutable: (msg: string, fields?: ReadonlyArray<FieldError>) => AccountingError;
792
+ readonly fiscal: (msg: string, fields?: ReadonlyArray<FieldError>) => AccountingError;
612
793
  };
613
794
  //#endregion
614
795
  //#region src/utils/filter-builder.d.ts
@@ -690,4 +871,4 @@ interface PostingResult {
690
871
  idempotencyKeys?: string[];
691
872
  }
692
873
  //#endregion
693
- export { type AccountForeignBalance, type AccountRepository, type AccountType, AccountingEngine, type AccountingEngineConfig, AccountingError, type AgedBalanceOptions, type AgedBalanceParams, type AgedBalanceReport, type AgedBalanceRow, type AgedBucketConfig, type AuditConfig, type BalanceSheetReport, type BudgetVsActualOptions, type BudgetVsActualParams, type BudgetVsActualReport, type BudgetVsActualRow, type BulkCreateInput, type BulkCreateResult, CATEGORIES, CATEGORY_KEYS, CURRENCIES, type CashFlowCategory, type CashFlowReport, type CashFlowSection, type CategoryKey, type Cents, type CountryPack, type CountryPackInput, type Currency, DEFAULT_BUCKETS, type DateOption, type DateRange, type DimensionBreakdownOptions, type DimensionBreakdownParams, type DimensionBreakdownReport, type DimensionBreakdownRow, type DimensionDefinition, type EntryState, Errors, type ExportField, type ExportFieldMap, type FlatJournalRow, type GeneralLedgerAccount, type GeneralLedgerReport, type IncomeStatementReport, JOURNAL_CODES, JOURNAL_TYPES, type JournalEntryRepository, type JournalItem, type JournalSchemaOptions, type JournalType, type LedgerEntry, type LedgerModels, type LedgerPaginationConfig, type LedgerRepositories, type LedgerRepositoryPlugins, type Logger, type MainType, type ModelNames, Money, type MultiCurrencyConfig, type MultiTenantConfig, type NormalBalance, type PopulatedJournalEntry, type PostOptions, type PostingContract, type PostingResult, type ReconcileParams, type ReconciliationRepository, type ReportAccount, type ReportCategory, type ReportGroup, type ResolvedModelNames, type RevaluationOptions, type RevaluationParams, type RevaluationRate, type RevaluationReport, type RevaluationResult, type ReverseOptions, type ReverseResult, type SchemaOptions, type SeedOptions, type SeedResult, type SessionResult, type StatementType, type StrictnessConfig, type SubledgerJournalItem, type SubledgerPostingInput, type TaxCode, type TaxCodesByRegion, type TaxDetail, type TaxMetadata, type TaxReport, type TaxReportLine, type TaxReportTemplate, type TaxReturnSummary, type TotalAccountOp, type TrialBalanceReport, type TrialBalanceRow, acquireSession, add, allocate, buildAccountTypeMap, buildDimensionFields, buildDimensionIndexes, buildItemFilters, buildRevaluationEntry, calculateTotal, closeFiscalPeriod, computeEndingBalance, computeRevaluation, createAccountSchema, createAccountingEngine, createFiscalPeriodSchema, createJournalEntrySchema, createModels, createRepositories, dateLockPlugin, defaultLogger, defineCountryPack, doubleEntryPlugin, exportToCsv, finalizeSession, fiscalLockPlugin, flattenJournalEntries, format, formatPlain, fromDecimal, generateAgedBalance, generateBalanceSheet, generateBudgetVsActual, generateCashFlow, generateDimensionBreakdown, generateGeneralLedger, generateIncomeStatement, generateRevaluation, generateTrialBalance, getCurrency, getCustomJournalTypes, getDateRange, getFiscalYearStart, getJournalType, getJournalTypeCodes, getMinorUnit, getNormalBalance, idempotencyPlugin, isBalanceSheet, isIncomeStatement, isValidCategory, isValidCurrency, isValidJournalType, isVirtualTaxAccount, multiply, parseCents, percentage, quickbooksFieldMap, registerJournalType, reopenFiscalPeriod, resolveModelNames, splitTaxExclusive, splitTaxInclusive, subtract, toDecimal, universalFieldMap, wireAccountMethods, wireJournalEntryMethods, wireReconciliationMethods };
874
+ export { type AccountCode, type AccountForeignBalance, type AccountRepository, type AccountSummary, type AccountType, AccountingEngine, type AccountingEngineConfig, AccountingError, type ActorContext, type AgedBalanceOptions, type AgedBalanceParams, type AgedBalanceReport, type AgedBalanceRow, type AgedBucketConfig, type AuditConfig, type BalanceSheetReport, type BudgetVsActualOptions, type BudgetVsActualParams, type BudgetVsActualReport, type BudgetVsActualRow, type BulkCreateInput, type BulkCreateResult, CATEGORIES, CATEGORY_KEYS, CURRENCIES, type CashFlowCategory, type CashFlowReport, type CashFlowSection, type CategoryKey, type Cents, type CountryPack, type CountryPackInput, type Currency, DEFAULT_BUCKETS, type DateOption, type DateRange, type DimensionBreakdownOptions, type DimensionBreakdownParams, type DimensionBreakdownReport, type DimensionBreakdownRow, type DimensionDefinition, type EntryState, Errors, type ExportField, type ExportFieldMap, type FieldError, type FiscalPeriodSummary, type FlatJournalRow, type GeneralLedgerAccount, type GeneralLedgerReport, type IncomeStatementReport, type IntrospectAPI, JOURNAL_CODES, JOURNAL_TYPES, type JournalEntryRepository, type JournalItem, type JournalSchemaOptions, type JournalType, type LedgerEntry, type LedgerModels, type LedgerPaginationConfig, type LedgerRepositories, type LedgerRepositoryPlugins, type Logger, type MainType, type ModelNames, Money, type MultiCurrencyConfig, type MultiTenantConfig, type NormalBalance, type PopulatedJournalEntry, type PostOptions, type PostingContract, type PostingResult, type ReconcileParams, type ReconciliationRepository, type RecordAPI, type RecordAdjustmentInput, type RecordAdjustmentLine, type RecordExpenseInput, type RecordOptions, type RecordPaymentInput, type RecordSaleInput, type RecordTransferInput, type ReportAccount, type ReportCategory, type ReportDescriptor, type ReportGroup, type ResolvedModelNames, type RevaluationOptions, type RevaluationParams, type RevaluationRate, type RevaluationReport, type RevaluationResult, type ReverseOptions, type ReverseResult, type SchemaOptions, type SeedOptions, type SeedResult, type Cents$1 as SemanticCents, type SessionResult, type StatementType, type StrictnessConfig, type SubledgerJournalItem, type SubledgerPostingInput, type TaxCode, type TaxCodesByRegion, type TaxDetail, type TaxInput, type TaxMetadata, type TaxReport, type TaxReportLine, type TaxReportTemplate, type TaxReturnSummary, type TotalAccountOp, type TrialBalanceReport, type TrialBalanceRow, acquireSession, add, allocate, buildAccountTypeMap, buildDimensionFields, buildDimensionIndexes, buildItemFilters, buildRevaluationEntry, calculateTotal, closeFiscalPeriod, computeEndingBalance, computeRevaluation, createAccountingEngine, createModels, createRepositories, dateLockPlugin, defaultLogger, defineCountryPack, doubleEntryPlugin, exportToCsv, finalizeSession, fiscalLockPlugin, flattenJournalEntries, format, formatPlain, fromDecimal, generateAgedBalance, generateBalanceSheet, generateBudgetVsActual, generateCashFlow, generateDimensionBreakdown, generateGeneralLedger, generateIncomeStatement, generateRevaluation, generateTrialBalance, getCurrency, getCustomJournalTypes, getDateRange, getFiscalYearStart, getJournalType, getJournalTypeCodes, getMinorUnit, getNormalBalance, idempotencyPlugin, isBalanceSheet, isIncomeStatement, isValidCategory, isValidCurrency, isValidJournalType, isVirtualTaxAccount, multiply, parseCents, percentage, quickbooksFieldMap, registerJournalType, reopenFiscalPeriod, resolveModelNames, splitTaxExclusive, splitTaxInclusive, subtract, toDecimal, universalFieldMap };