@whocomply/ledger 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +64 -0
- package/dist/index.cjs +559 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +590 -0
- package/dist/index.d.ts +590 -0
- package/dist/index.js +530 -0
- package/dist/index.js.map +1 -0
- package/package.json +58 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/http.ts","../src/resources/accounts.ts","../src/resources/balances.ts","../src/resources/events.ts","../src/resources/currencies.ts","../src/resources/periods.ts","../src/resources/recurring.ts","../src/resources/reports.ts","../src/resources/transactions.ts"],"sourcesContent":["import { HttpClient } from './http';\nimport type { LedgerClientOptions } from './http';\nimport { AccountsResource } from './resources/accounts';\nimport { BalancesResource } from './resources/balances';\nimport { EventsResource } from './resources/events';\nimport { CurrenciesResource } from './resources/currencies';\nimport { PeriodsResource } from './resources/periods';\nimport { RecurringJournalsResource } from './resources/recurring';\nimport { ReportsResource } from './resources/reports';\nimport { TransactionsResource } from './resources/transactions';\n\nexport class LedgerClient {\n readonly accounts: AccountsResource;\n readonly balances: BalancesResource;\n readonly events: EventsResource;\n readonly transactions: TransactionsResource;\n readonly currencies: CurrenciesResource;\n readonly periods: PeriodsResource;\n readonly recurringJournals: RecurringJournalsResource;\n readonly reports: ReportsResource;\n\n constructor(options: LedgerClientOptions) {\n const http = new HttpClient(options);\n this.accounts = new AccountsResource(http);\n this.balances = new BalancesResource(http);\n this.events = new EventsResource(http);\n this.transactions = new TransactionsResource(http);\n this.currencies = new CurrenciesResource(http);\n this.periods = new PeriodsResource(http);\n this.recurringJournals = new RecurringJournalsResource(http);\n this.reports = new ReportsResource(http);\n }\n}\n\nexport { LedgerApiError, MissingIdempotencyKeyError } from './errors';\nexport type { InsufficientBalanceDetails, LedgerErrorCode } from './errors';\nexport type { LedgerClientOptions, RequestOptions } from './http';\nexport * from './types';\n","/** Stable machine-readable error codes; branch on these, never on message text. */\nexport type LedgerErrorCode =\n | 'INSUFFICIENT_BALANCE'\n | 'UNBALANCED_TRANSACTION'\n | 'AMOUNT_PRECISION'\n | 'AMOUNT_TOO_LARGE'\n | 'CURRENCY_DEACTIVATED'\n | 'CURRENCY_PRECISION'\n | 'PERIOD_CLOSED'\n | 'ALREADY_REVERSED'\n | 'CANNOT_REVERSE_UNPOSTED'\n | 'ACCOUNT_NOT_FOUND'\n | 'ACCOUNT_EXISTS'\n | 'IDEMPOTENCY_CONFLICT'\n | 'VALIDATION_ERROR'\n | 'NOT_DRAFT'\n | 'SELF_APPROVAL'\n | 'TRANSACTION_NOT_FOUND'\n | (string & {});\n\n/** Structured detail attached to INSUFFICIENT_BALANCE errors. */\nexport interface InsufficientBalanceDetails {\n account_code: string;\n currency: string;\n /** Decimal strings; render customer copy from these, never parse prose. */\n attempted: string;\n available: string;\n}\n\n/** Error raised for any non-success response from the ledger API. */\nexport class LedgerApiError extends Error {\n /** HTTP status code */\n readonly status: number;\n /** Alias for status, per the Alphaex integration contract. */\n readonly httpStatus: number;\n /** Stable machine-readable code (absent on transport-level failures). */\n readonly code?: LedgerErrorCode;\n /** Structured error context (e.g. InsufficientBalanceDetails). */\n readonly details?: unknown;\n /** Raw response body, when one could be read */\n readonly body?: unknown;\n\n constructor(status: number, message: string, options: { code?: string; details?: unknown; body?: unknown } = {}) {\n super(message);\n this.name = 'LedgerApiError';\n this.status = status;\n this.httpStatus = status;\n this.code = options.code;\n this.details = options.details;\n this.body = options.body;\n }\n\n /** True for 409s: double reversals, closed periods, existing resources. */\n get isConflict(): boolean {\n return this.status === 409;\n }\n\n /** Typed accessor for INSUFFICIENT_BALANCE detail. */\n get insufficientBalance(): InsufficientBalanceDetails | undefined {\n if (this.code !== 'INSUFFICIENT_BALANCE') {\n return undefined;\n }\n return this.details as InsufficientBalanceDetails;\n }\n}\n\n/** Thrown in strict idempotency mode when a mutating call omits the key. */\nexport class MissingIdempotencyKeyError extends Error {\n constructor(method: string) {\n super(`${method} requires an explicit idempotencyKey (client has requireIdempotencyKey: true)`);\n this.name = 'MissingIdempotencyKeyError';\n }\n}\n","import { LedgerApiError } from './errors';\n\nexport interface LedgerClientOptions {\n /** Ledger API origin, e.g. https://ledger.internal.example.com or http://localhost:8080 */\n baseUrl: string;\n /** Tenant slug all requests are scoped to */\n tenant: string;\n /** Machine access: sent as X-API-Key. Create keys in the dashboard under Settings. */\n apiKey?: string;\n /** User access: sent as Authorization: Bearer. Mostly for dashboards. */\n token?: string;\n /** Override fetch (testing, custom agents). Defaults to globalThis.fetch. */\n fetch?: typeof fetch;\n /** Per-request timeout in milliseconds. No timeout when omitted. */\n timeoutMs?: number;\n /**\n * Strict idempotency: posting/reversal/draft methods throw when called\n * without an explicit idempotencyKey instead of auto-generating one.\n */\n requireIdempotencyKey?: boolean;\n}\n\n/** Per-call options accepted by every SDK method. */\nexport interface RequestOptions {\n /** Abort the request (combined with the client timeout when both are set). */\n signal?: AbortSignal;\n}\n\ntype Query = Record<string, string | number | undefined>;\n\ninterface InternalRequestOptions {\n query?: Query;\n body?: unknown;\n /** Return the raw response text instead of unwrapping the JSON envelope (CSV exports). */\n raw?: boolean;\n signal?: AbortSignal;\n}\n\nexport class HttpClient {\n private readonly baseUrl: string;\n private readonly headers: Record<string, string>;\n private readonly fetchImpl: typeof fetch;\n private readonly timeoutMs?: number;\n readonly tenant: string;\n readonly requireIdempotencyKey: boolean;\n\n constructor(options: LedgerClientOptions) {\n if (!options.baseUrl) {\n throw new Error('baseUrl is required');\n }\n if (!options.tenant) {\n throw new Error('tenant is required');\n }\n if (!options.apiKey && !options.token) {\n throw new Error('either apiKey or token is required');\n }\n\n this.baseUrl = options.baseUrl.replace(/\\/+$/, '');\n this.tenant = options.tenant;\n this.fetchImpl = options.fetch ?? globalThis.fetch;\n this.timeoutMs = options.timeoutMs;\n this.requireIdempotencyKey = options.requireIdempotencyKey ?? false;\n this.headers = { 'Content-Type': 'application/json' };\n if (options.apiKey) {\n this.headers['X-API-Key'] = options.apiKey;\n } else if (options.token) {\n this.headers['Authorization'] = `Bearer ${options.token}`;\n }\n }\n\n /** Path inside the tenant scope, e.g. tenantPath('/accounts') */\n tenantPath(path: string): string {\n return `/tenants/${encodeURIComponent(this.tenant)}${path}`;\n }\n\n private effectiveSignal(callerSignal?: AbortSignal): AbortSignal | undefined {\n const timeoutSignal = this.timeoutMs ? AbortSignal.timeout(this.timeoutMs) : undefined;\n if (callerSignal && timeoutSignal) {\n return typeof AbortSignal.any === 'function'\n ? AbortSignal.any([callerSignal, timeoutSignal])\n : callerSignal;\n }\n return callerSignal ?? timeoutSignal;\n }\n\n async request<T>(method: string, path: string, options: InternalRequestOptions = {}): Promise<T> {\n let url = `${this.baseUrl}/api/v1${path}`;\n if (options.query) {\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(options.query)) {\n if (value !== undefined && value !== '') {\n params.set(key, String(value));\n }\n }\n const qs = params.toString();\n if (qs) {\n url += `?${qs}`;\n }\n }\n\n const response = await this.fetchImpl(url, {\n method,\n headers: this.headers,\n body: options.body === undefined ? undefined : JSON.stringify(options.body),\n signal: this.effectiveSignal(options.signal),\n });\n\n if (options.raw) {\n const text = await response.text();\n if (!response.ok) {\n throw new LedgerApiError(response.status, text || response.statusText, { body: text });\n }\n return text as T;\n }\n\n let envelope: { success?: boolean; data?: T; error?: string; code?: string; details?: unknown } | undefined;\n try {\n envelope = (await response.json()) as typeof envelope;\n } catch {\n envelope = undefined;\n }\n\n if (!response.ok || !envelope || envelope.success !== true) {\n const message = envelope?.error ?? `request failed with status ${response.status}`;\n throw new LedgerApiError(response.status, message, {\n code: envelope?.code,\n details: envelope?.details,\n body: envelope,\n });\n }\n\n return envelope.data as T;\n }\n}\n\n/** Idempotency key generator used when the caller does not supply one. */\nexport const generateIdempotencyKey = (): string => {\n const cryptoApi = globalThis.crypto as Crypto | undefined;\n if (cryptoApi && 'randomUUID' in cryptoApi) {\n return cryptoApi.randomUUID();\n }\n return `idem-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 12)}`;\n};\n","import type { HttpClient, RequestOptions } from '../http';\nimport type {\n Account,\n AccountBalance,\n AccountStats,\n AccountsPage,\n AsOfBalance,\n CreateAccountInput,\n ListAccountsParams,\n UpdateAccountInput,\n} from '../types';\n\nexport class AccountsResource {\n constructor(private readonly http: HttpClient) {}\n\n create(input: CreateAccountInput, options: RequestOptions = {}): Promise<Account> {\n return this.http.request('POST', this.http.tenantPath('/accounts'), { body: input, signal: options.signal });\n }\n\n list(params: ListAccountsParams = {}, options: RequestOptions = {}): Promise<AccountsPage> {\n return this.http.request('GET', this.http.tenantPath('/accounts'), {\n signal: options.signal,\n query: {\n account_type: params.accountType,\n parent_code: params.parentCode,\n currency: params.currency,\n search: params.search,\n page: params.page,\n page_size: params.pageSize,\n },\n });\n }\n\n get(accountId: string, options: RequestOptions = {}): Promise<Account> {\n return this.http.request('GET', this.http.tenantPath(`/accounts/${accountId}`), { signal: options.signal });\n }\n\n getByCode(code: string, options: RequestOptions = {}): Promise<Account> {\n return this.http.request('GET', this.http.tenantPath(`/accounts/code/${encodeURIComponent(code)}`), { signal: options.signal });\n }\n\n update(accountId: string, input: UpdateAccountInput, options: RequestOptions = {}): Promise<Account> {\n return this.http.request('PUT', this.http.tenantPath(`/accounts/${accountId}`), { body: input, signal: options.signal });\n }\n\n deactivate(accountId: string, options: RequestOptions = {}): Promise<{ message: string }> {\n return this.http.request('DELETE', this.http.tenantPath(`/accounts/${accountId}`), { signal: options.signal });\n }\n\n /** Current materialized balance. Currency defaults to the tenant base currency. */\n balance(accountId: string, options: RequestOptions & { currency?: string } = {}): Promise<AccountBalance> {\n return this.http.request('GET', this.http.tenantPath(`/accounts/${accountId}/balance`), {\n signal: options.signal,\n query: { currency: options.currency },\n });\n }\n\n /** Journal-derived balance through the end of a past day (YYYY-MM-DD, UTC). */\n balanceAsOf(accountId: string, asOf: string, options: RequestOptions & { currency?: string } = {}): Promise<AsOfBalance> {\n return this.http.request('GET', this.http.tenantPath(`/accounts/${accountId}/balance`), {\n signal: options.signal,\n query: { as_of: asOf, currency: options.currency },\n });\n }\n\n hierarchy(options: RequestOptions = {}): Promise<Account[]> {\n return this.http.request('GET', this.http.tenantPath('/accounts/hierarchy'), { signal: options.signal });\n }\n\n stats(options: RequestOptions = {}): Promise<AccountStats> {\n return this.http.request('GET', this.http.tenantPath('/accounts/stats'), { signal: options.signal });\n }\n}\n","import type { HttpClient, RequestOptions } from '../http';\nimport type { BalancesPage, ListBalancesParams } from '../types';\n\nexport class BalancesResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Bulk balances: every (account, currency) row with its monotonic\n * version. Filter by codePrefix/codeSuffix, currency, or account\n * metadata containment (e.g. { org_id: '...' }).\n */\n list(params: ListBalancesParams = {}, options: RequestOptions = {}): Promise<BalancesPage> {\n const metadata = params.metadata && Object.keys(params.metadata).length > 0\n ? Object.entries(params.metadata).map(([key, value]) => `${key}:${value}`).join(',')\n : undefined;\n return this.http.request('GET', this.http.tenantPath('/balances'), {\n query: {\n limit: params.limit,\n offset: params.offset,\n code_prefix: params.codePrefix,\n code_suffix: params.codeSuffix,\n currency: params.currency,\n metadata,\n },\n signal: options.signal,\n });\n }\n}\n","import type { HttpClient, RequestOptions } from '../http';\nimport type { EventsPage } from '../types';\n\nexport class EventsResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Durable event feed, strictly ordered by sequence. Poll with\n * afterId = the last sequence you processed; store next_cursor.\n */\n list(params: { afterId?: number; limit?: number } = {}, options: RequestOptions = {}): Promise<EventsPage> {\n return this.http.request('GET', this.http.tenantPath('/events'), {\n query: {\n after_id: params.afterId,\n limit: params.limit,\n },\n signal: options.signal,\n });\n }\n}\n","import type { HttpClient, RequestOptions } from '../http';\nimport type { Currency, RegisterCurrencyInput, UpdateCurrencyInput } from '../types';\n\nexport class CurrenciesResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Register a currency with its precision policy. Postings beyond the\n * exponent's decimal places are rejected. Unregistered currencies fall\n * back to the storage maximum of 18 decimal places.\n */\n register(input: RegisterCurrencyInput, options: RequestOptions = {}): Promise<Currency> {\n return this.http.request('POST', this.http.tenantPath('/currencies'), { body: input, signal: options.signal });\n }\n\n list(options: RequestOptions = {}): Promise<Currency[]> {\n return this.http.request('GET', this.http.tenantPath('/currencies'), { signal: options.signal });\n }\n\n update(code: string, input: UpdateCurrencyInput, options: RequestOptions = {}): Promise<Currency> {\n return this.http.request('PUT', this.http.tenantPath(`/currencies/${encodeURIComponent(code)}`), {\n signal: options.signal,\n body: input,\n });\n }\n}\n","import type { HttpClient, RequestOptions } from '../http';\nimport type { AccountingPeriod, CreatePeriodInput } from '../types';\n\nexport class PeriodsResource {\n constructor(private readonly http: HttpClient) {}\n\n /** Periods of one tenant may not overlap; violations raise a 409. */\n create(input: CreatePeriodInput, options: RequestOptions = {}): Promise<AccountingPeriod> {\n return this.http.request('POST', this.http.tenantPath('/periods'), { body: input, signal: options.signal });\n }\n\n list(options: RequestOptions = {}): Promise<AccountingPeriod[]> {\n return this.http.request('GET', this.http.tenantPath('/periods'), { signal: options.signal });\n }\n\n /**\n * Close a period. Enforced by the database: nothing can post into a\n * closed period, and posting attempts raise a 409.\n */\n close(periodId: string, options: RequestOptions = {}): Promise<AccountingPeriod> {\n return this.http.request('POST', this.http.tenantPath(`/periods/${periodId}/close`), { signal: options.signal });\n }\n\n reopen(periodId: string, options: RequestOptions = {}): Promise<AccountingPeriod> {\n return this.http.request('POST', this.http.tenantPath(`/periods/${periodId}/reopen`), { signal: options.signal });\n }\n}\n","import type { HttpClient, RequestOptions } from '../http';\nimport type { CreateRecurringJournalInput, RecurringJournal } from '../types';\n\nexport class RecurringJournalsResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Register a repeating journal. Each occurrence posts exactly once: the\n * worker derives the idempotency key from (schedule id, run date).\n */\n create(input: CreateRecurringJournalInput, options: RequestOptions = {}): Promise<RecurringJournal> {\n return this.http.request('POST', this.http.tenantPath('/recurring-journals'), { body: input, signal: options.signal });\n }\n\n list(options: RequestOptions = {}): Promise<RecurringJournal[]> {\n return this.http.request('GET', this.http.tenantPath('/recurring-journals'), { signal: options.signal });\n }\n\n pause(scheduleId: string, options: RequestOptions = {}): Promise<RecurringJournal> {\n return this.http.request('POST', this.http.tenantPath(`/recurring-journals/${scheduleId}/pause`), { signal: options.signal });\n }\n\n resume(scheduleId: string, options: RequestOptions = {}): Promise<RecurringJournal> {\n return this.http.request('POST', this.http.tenantPath(`/recurring-journals/${scheduleId}/resume`), { signal: options.signal });\n }\n}\n","import type { HttpClient, RequestOptions } from '../http';\nimport type { BalanceSheet, FxExposure, GeneralLedger, ProfitAndLoss, TrialBalance } from '../types';\n\nconst dimensionsParam = (dimensions?: Record<string, string>): string | undefined => {\n if (!dimensions || Object.keys(dimensions).length === 0) {\n return undefined;\n }\n return Object.entries(dimensions)\n .map(([key, value]) => `${key}:${value}`)\n .join(',');\n};\n\nexport class ReportsResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Trial balance derived from posted journal lines, grouped by currency.\n * asOf (YYYY-MM-DD) means \"through the end of that day, UTC\"; defaults\n * to now.\n */\n trialBalance(options: RequestOptions & { asOf?: string } = {}): Promise<TrialBalance> {\n return this.http.request('GET', this.http.tenantPath('/reports/trial-balance'), {\n signal: options.signal,\n query: { as_of: options.asOf },\n });\n }\n\n /** Revenue and expenses over an inclusive date range, optionally filtered by dimensions. */\n profitAndLoss(options: RequestOptions & { startDate: string; endDate: string; dimensions?: Record<string, string> }): Promise<ProfitAndLoss> {\n return this.http.request('GET', this.http.tenantPath('/reports/profit-and-loss'), {\n signal: options.signal,\n query: {\n start_date: options.startDate,\n end_date: options.endDate,\n dimensions: dimensionsParam(options.dimensions),\n },\n });\n }\n\n /** Assets, liabilities, and equity (with computed retained earnings) as of a date. */\n balanceSheet(options: RequestOptions & { asOf?: string } = {}): Promise<BalanceSheet> {\n return this.http.request('GET', this.http.tenantPath('/reports/balance-sheet'), {\n signal: options.signal,\n query: { as_of: options.asOf },\n });\n }\n\n /** One account's activity with opening, running, and closing balances. */\n generalLedger(options: RequestOptions & { accountCode: string; startDate: string; endDate: string; currency?: string }): Promise<GeneralLedger> {\n return this.http.request('GET', this.http.tenantPath('/reports/general-ledger'), {\n signal: options.signal,\n query: {\n account_code: options.accountCode,\n start_date: options.startDate,\n end_date: options.endDate,\n currency: options.currency,\n },\n });\n }\n\n /** Per-currency net positions with base equivalents at the provided rates. */\n fxExposure(options: RequestOptions & { rates?: Record<string, string>; asOf?: string } = {}): Promise<FxExposure> {\n const rates = options.rates\n ? Object.entries(options.rates).map(([code, rate]) => `${code}:${rate}`).join(',')\n : undefined;\n return this.http.request('GET', this.http.tenantPath('/reports/fx-exposure'), {\n signal: options.signal,\n query: { rates, as_of: options.asOf },\n });\n }\n\n /**\n * Posted journals as a Xero manual-journal import CSV (raw string).\n * Dates are inclusive. Currency defaults to the tenant base currency.\n */\n xeroJournalsCsv(options: RequestOptions & { startDate: string; endDate: string; currency?: string }): Promise<string> {\n return this.http.request('GET', this.http.tenantPath('/reports/xero-journals'), {\n signal: options.signal,\n query: {\n start_date: options.startDate,\n end_date: options.endDate,\n currency: options.currency,\n },\n raw: true,\n });\n }\n}\n","import { generateIdempotencyKey } from '../http';\nimport type { HttpClient, RequestOptions } from '../http';\nimport { MissingIdempotencyKeyError } from '../errors';\nimport type {\n ListTransactionsParams,\n PostEntryInput,\n Transaction,\n TransactionLine,\n TransactionNote,\n TransactionsPage,\n} from '../types';\n\nexport class TransactionsResource {\n constructor(private readonly http: HttpClient) {}\n\n private idempotencyKey(method: string, provided?: string): string {\n if (provided) {\n return provided;\n }\n if (this.http.requireIdempotencyKey) {\n throw new MissingIdempotencyKeyError(method);\n }\n return generateIdempotencyKey();\n }\n\n /**\n * Post a balanced double-entry transaction. Debits must equal credits per\n * currency or the API rejects with UNBALANCED_TRANSACTION. posted_at\n * backdates the posting and requires the transactions:backdate scope.\n */\n post(input: PostEntryInput, options: RequestOptions = {}): Promise<Transaction> {\n const { idempotencyKey, postedAt, ...rest } = input;\n return this.http.request('POST', this.http.tenantPath('/transactions/double-entry'), {\n body: {\n ...rest,\n idempotency_key: this.idempotencyKey('transactions.post', idempotencyKey),\n ...(postedAt ? { posted_at: postedAt } : {}),\n },\n signal: options.signal,\n });\n }\n\n get(transactionId: string, options: RequestOptions & { includeLines?: boolean } = {}): Promise<Transaction> {\n return this.http.request('GET', this.http.tenantPath(`/transactions/${transactionId}`), {\n query: { include: options.includeLines ? 'lines' : undefined },\n signal: options.signal,\n });\n }\n\n lines(transactionId: string, options: RequestOptions = {}): Promise<TransactionLine[]> {\n return this.http.request('GET', this.http.tenantPath(`/transactions/${transactionId}/lines`), {\n signal: options.signal,\n });\n }\n\n list(params: ListTransactionsParams = {}, options: RequestOptions = {}): Promise<TransactionsPage> {\n return this.http.request('GET', this.http.tenantPath('/transactions'), {\n query: {\n limit: params.limit,\n offset: params.offset,\n account_code: params.accountCode,\n reference: params.reference,\n status: params.status,\n start_date: params.startDate,\n end_date: params.endDate,\n include: params.includeLines ? 'lines' : undefined,\n },\n signal: options.signal,\n });\n }\n\n /**\n * Maker-checker: store a fully validated entry with zero balance impact.\n * Balances apply only when a DIFFERENT actor approves.\n */\n draft(input: PostEntryInput, options: RequestOptions = {}): Promise<Transaction> {\n const { idempotencyKey, postedAt, ...rest } = input;\n void postedAt;\n return this.http.request('POST', this.http.tenantPath('/transactions/draft'), {\n body: {\n ...rest,\n idempotency_key: this.idempotencyKey('transactions.draft', idempotencyKey),\n },\n signal: options.signal,\n });\n }\n\n /** Approve a draft (requires the transactions:approve scope and a different actor). */\n approve(transactionId: string, options: RequestOptions = {}): Promise<Transaction> {\n return this.http.request('POST', this.http.tenantPath(`/transactions/${transactionId}/approve`), {\n signal: options.signal,\n });\n }\n\n /** Reject a draft; it never had balance impact. */\n reject(transactionId: string, options: RequestOptions = {}): Promise<Transaction> {\n return this.http.request('POST', this.http.tenantPath(`/transactions/${transactionId}/reject`), {\n signal: options.signal,\n });\n }\n\n /** Append an immutable note (audit support). */\n addNote(transactionId: string, note: string, options: RequestOptions = {}): Promise<TransactionNote> {\n return this.http.request('POST', this.http.tenantPath(`/transactions/${transactionId}/notes`), {\n body: { note },\n signal: options.signal,\n });\n }\n\n listNotes(transactionId: string, options: RequestOptions = {}): Promise<TransactionNote[]> {\n return this.http.request('GET', this.http.tenantPath(`/transactions/${transactionId}/notes`), {\n signal: options.signal,\n });\n }\n\n /**\n * Post a reversal: a new transaction mirroring the original with debits\n * and credits swapped, linked via reverses_transaction_id. A transaction\n * can be reversed at most once; a second attempt raises ALREADY_REVERSED.\n */\n reverse(\n transactionId: string,\n reverseOptions: { idempotencyKey?: string; description?: string; metadata?: Record<string, unknown> } = {},\n options: RequestOptions = {}\n ): Promise<Transaction> {\n return this.http.request('POST', this.http.tenantPath(`/transactions/${transactionId}/reverse`), {\n body: {\n idempotency_key: this.idempotencyKey('transactions.reverse', reverseOptions.idempotencyKey),\n description: reverseOptions.description,\n metadata: reverseOptions.metadata,\n },\n signal: options.signal,\n });\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,590 @@
|
|
|
1
|
+
interface LedgerClientOptions {
|
|
2
|
+
/** Ledger API origin, e.g. https://ledger.internal.example.com or http://localhost:8080 */
|
|
3
|
+
baseUrl: string;
|
|
4
|
+
/** Tenant slug all requests are scoped to */
|
|
5
|
+
tenant: string;
|
|
6
|
+
/** Machine access: sent as X-API-Key. Create keys in the dashboard under Settings. */
|
|
7
|
+
apiKey?: string;
|
|
8
|
+
/** User access: sent as Authorization: Bearer. Mostly for dashboards. */
|
|
9
|
+
token?: string;
|
|
10
|
+
/** Override fetch (testing, custom agents). Defaults to globalThis.fetch. */
|
|
11
|
+
fetch?: typeof fetch;
|
|
12
|
+
/** Per-request timeout in milliseconds. No timeout when omitted. */
|
|
13
|
+
timeoutMs?: number;
|
|
14
|
+
/**
|
|
15
|
+
* Strict idempotency: posting/reversal/draft methods throw when called
|
|
16
|
+
* without an explicit idempotencyKey instead of auto-generating one.
|
|
17
|
+
*/
|
|
18
|
+
requireIdempotencyKey?: boolean;
|
|
19
|
+
}
|
|
20
|
+
/** Per-call options accepted by every SDK method. */
|
|
21
|
+
interface RequestOptions {
|
|
22
|
+
/** Abort the request (combined with the client timeout when both are set). */
|
|
23
|
+
signal?: AbortSignal;
|
|
24
|
+
}
|
|
25
|
+
type Query = Record<string, string | number | undefined>;
|
|
26
|
+
interface InternalRequestOptions {
|
|
27
|
+
query?: Query;
|
|
28
|
+
body?: unknown;
|
|
29
|
+
/** Return the raw response text instead of unwrapping the JSON envelope (CSV exports). */
|
|
30
|
+
raw?: boolean;
|
|
31
|
+
signal?: AbortSignal;
|
|
32
|
+
}
|
|
33
|
+
declare class HttpClient {
|
|
34
|
+
private readonly baseUrl;
|
|
35
|
+
private readonly headers;
|
|
36
|
+
private readonly fetchImpl;
|
|
37
|
+
private readonly timeoutMs?;
|
|
38
|
+
readonly tenant: string;
|
|
39
|
+
readonly requireIdempotencyKey: boolean;
|
|
40
|
+
constructor(options: LedgerClientOptions);
|
|
41
|
+
/** Path inside the tenant scope, e.g. tenantPath('/accounts') */
|
|
42
|
+
tenantPath(path: string): string;
|
|
43
|
+
private effectiveSignal;
|
|
44
|
+
request<T>(method: string, path: string, options?: InternalRequestOptions): Promise<T>;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
type AccountType = 'asset' | 'liability' | 'equity' | 'revenue' | 'expense';
|
|
48
|
+
type EntrySide = 'debit' | 'credit';
|
|
49
|
+
type TransactionStatus = 'draft' | 'pending' | 'posted' | 'failed' | 'rejected';
|
|
50
|
+
type PeriodStatus = 'open' | 'closed';
|
|
51
|
+
interface Account {
|
|
52
|
+
id: string;
|
|
53
|
+
code: string;
|
|
54
|
+
name: string;
|
|
55
|
+
account_type: AccountType;
|
|
56
|
+
parent_code?: string;
|
|
57
|
+
currency: string;
|
|
58
|
+
allow_negative: boolean;
|
|
59
|
+
is_active: boolean;
|
|
60
|
+
metadata?: Record<string, unknown>;
|
|
61
|
+
created_at: string;
|
|
62
|
+
updated_at: string;
|
|
63
|
+
}
|
|
64
|
+
interface CreateAccountInput {
|
|
65
|
+
code: string;
|
|
66
|
+
name: string;
|
|
67
|
+
account_type: AccountType;
|
|
68
|
+
parent_code?: string;
|
|
69
|
+
currency?: string;
|
|
70
|
+
allow_negative?: boolean;
|
|
71
|
+
metadata?: Record<string, unknown>;
|
|
72
|
+
}
|
|
73
|
+
interface UpdateAccountInput {
|
|
74
|
+
name?: string;
|
|
75
|
+
allow_negative?: boolean;
|
|
76
|
+
metadata?: Record<string, unknown>;
|
|
77
|
+
}
|
|
78
|
+
interface AccountsPage {
|
|
79
|
+
accounts: Account[];
|
|
80
|
+
page: number;
|
|
81
|
+
page_size: number;
|
|
82
|
+
total: number;
|
|
83
|
+
total_pages: number;
|
|
84
|
+
}
|
|
85
|
+
interface ListAccountsParams {
|
|
86
|
+
accountType?: AccountType;
|
|
87
|
+
parentCode?: string;
|
|
88
|
+
currency?: string;
|
|
89
|
+
search?: string;
|
|
90
|
+
page?: number;
|
|
91
|
+
pageSize?: number;
|
|
92
|
+
}
|
|
93
|
+
interface AccountBalance {
|
|
94
|
+
currency: string;
|
|
95
|
+
balance: string;
|
|
96
|
+
version: number;
|
|
97
|
+
}
|
|
98
|
+
interface AsOfBalance {
|
|
99
|
+
account_id: string;
|
|
100
|
+
currency: string;
|
|
101
|
+
balance: string;
|
|
102
|
+
as_of: string;
|
|
103
|
+
}
|
|
104
|
+
interface AccountStats {
|
|
105
|
+
total_accounts: number;
|
|
106
|
+
asset_accounts: number;
|
|
107
|
+
liability_accounts: number;
|
|
108
|
+
equity_accounts: number;
|
|
109
|
+
revenue_accounts: number;
|
|
110
|
+
expense_accounts: number;
|
|
111
|
+
currencies_count: number;
|
|
112
|
+
}
|
|
113
|
+
interface EntryLineInput {
|
|
114
|
+
account_code: string;
|
|
115
|
+
amount: string;
|
|
116
|
+
side: EntrySide;
|
|
117
|
+
currency: string;
|
|
118
|
+
/** Up to 4 flat string tags, e.g. { product: "wallet", region: "lagos" } */
|
|
119
|
+
dimensions?: Record<string, string>;
|
|
120
|
+
metadata?: Record<string, unknown>;
|
|
121
|
+
}
|
|
122
|
+
interface PostEntryInput {
|
|
123
|
+
description: string;
|
|
124
|
+
entries: EntryLineInput[];
|
|
125
|
+
/**
|
|
126
|
+
* Generated automatically when omitted, unless the client was built with
|
|
127
|
+
* requireIdempotencyKey: true (then omission throws).
|
|
128
|
+
*/
|
|
129
|
+
idempotencyKey?: string;
|
|
130
|
+
reference?: string;
|
|
131
|
+
/** RFC3339 backdating timestamp; requires the transactions:backdate scope. */
|
|
132
|
+
postedAt?: string;
|
|
133
|
+
metadata?: Record<string, unknown>;
|
|
134
|
+
}
|
|
135
|
+
interface Transaction {
|
|
136
|
+
id: string;
|
|
137
|
+
idempotency_key: string;
|
|
138
|
+
description: string;
|
|
139
|
+
reference?: string;
|
|
140
|
+
reverses_transaction_id?: string;
|
|
141
|
+
created_by?: string;
|
|
142
|
+
approved_by?: string;
|
|
143
|
+
status: TransactionStatus;
|
|
144
|
+
posted_at: string;
|
|
145
|
+
created_at: string;
|
|
146
|
+
metadata?: Record<string, unknown>;
|
|
147
|
+
}
|
|
148
|
+
interface TransactionLine {
|
|
149
|
+
id: string;
|
|
150
|
+
account_id: string;
|
|
151
|
+
account_code: string;
|
|
152
|
+
account_name: string;
|
|
153
|
+
amount: string;
|
|
154
|
+
side: EntrySide;
|
|
155
|
+
currency: string;
|
|
156
|
+
dimensions?: Record<string, string>;
|
|
157
|
+
created_at: string;
|
|
158
|
+
}
|
|
159
|
+
interface Pagination {
|
|
160
|
+
total: number;
|
|
161
|
+
limit: number;
|
|
162
|
+
offset: number;
|
|
163
|
+
has_more: boolean;
|
|
164
|
+
}
|
|
165
|
+
interface TransactionsPage {
|
|
166
|
+
transactions: Transaction[] | null;
|
|
167
|
+
pagination: Pagination;
|
|
168
|
+
}
|
|
169
|
+
interface ListTransactionsParams {
|
|
170
|
+
limit?: number;
|
|
171
|
+
offset?: number;
|
|
172
|
+
accountCode?: string;
|
|
173
|
+
/** Exact match on the consumer-supplied reference (ops lookup path). */
|
|
174
|
+
reference?: string;
|
|
175
|
+
/** Attach lines to every row in the same call (no N+1). */
|
|
176
|
+
includeLines?: boolean;
|
|
177
|
+
/** Filter by lifecycle state; 'draft' is the approvals queue */
|
|
178
|
+
status?: TransactionStatus;
|
|
179
|
+
/** YYYY-MM-DD; requires endDate */
|
|
180
|
+
startDate?: string;
|
|
181
|
+
/** YYYY-MM-DD; requires startDate */
|
|
182
|
+
endDate?: string;
|
|
183
|
+
}
|
|
184
|
+
interface Currency {
|
|
185
|
+
code: string;
|
|
186
|
+
name: string;
|
|
187
|
+
exponent: number;
|
|
188
|
+
is_active: boolean;
|
|
189
|
+
created_at: string;
|
|
190
|
+
updated_at: string;
|
|
191
|
+
}
|
|
192
|
+
interface RegisterCurrencyInput {
|
|
193
|
+
code: string;
|
|
194
|
+
/** Decimal places enforced on postings: NGN 2, USDT 6, BTC 8, ETH 18 */
|
|
195
|
+
exponent: number;
|
|
196
|
+
name?: string;
|
|
197
|
+
}
|
|
198
|
+
interface UpdateCurrencyInput {
|
|
199
|
+
name?: string;
|
|
200
|
+
exponent?: number;
|
|
201
|
+
is_active?: boolean;
|
|
202
|
+
}
|
|
203
|
+
interface AccountingPeriod {
|
|
204
|
+
id: string;
|
|
205
|
+
name: string;
|
|
206
|
+
starts_on: string;
|
|
207
|
+
ends_on: string;
|
|
208
|
+
status: PeriodStatus;
|
|
209
|
+
closed_at?: string;
|
|
210
|
+
created_at: string;
|
|
211
|
+
updated_at: string;
|
|
212
|
+
}
|
|
213
|
+
interface CreatePeriodInput {
|
|
214
|
+
name: string;
|
|
215
|
+
/** YYYY-MM-DD */
|
|
216
|
+
starts_on: string;
|
|
217
|
+
/** YYYY-MM-DD */
|
|
218
|
+
ends_on: string;
|
|
219
|
+
}
|
|
220
|
+
interface TrialBalanceRow {
|
|
221
|
+
account_id: string;
|
|
222
|
+
code: string;
|
|
223
|
+
name: string;
|
|
224
|
+
account_type: AccountType;
|
|
225
|
+
debit: string;
|
|
226
|
+
credit: string;
|
|
227
|
+
}
|
|
228
|
+
interface TrialBalanceCurrencyGroup {
|
|
229
|
+
currency: string;
|
|
230
|
+
rows: TrialBalanceRow[];
|
|
231
|
+
total_debit: string;
|
|
232
|
+
total_credit: string;
|
|
233
|
+
balanced: boolean;
|
|
234
|
+
}
|
|
235
|
+
interface TrialBalance {
|
|
236
|
+
as_of: string;
|
|
237
|
+
currencies: TrialBalanceCurrencyGroup[];
|
|
238
|
+
}
|
|
239
|
+
interface TransactionNote {
|
|
240
|
+
id: string;
|
|
241
|
+
author_id?: string;
|
|
242
|
+
note: string;
|
|
243
|
+
created_at: string;
|
|
244
|
+
}
|
|
245
|
+
interface StatementRow {
|
|
246
|
+
account_id: string;
|
|
247
|
+
code: string;
|
|
248
|
+
name: string;
|
|
249
|
+
amount: string;
|
|
250
|
+
}
|
|
251
|
+
interface ProfitAndLossCurrency {
|
|
252
|
+
currency: string;
|
|
253
|
+
revenue: StatementRow[] | null;
|
|
254
|
+
expenses: StatementRow[] | null;
|
|
255
|
+
total_revenue: string;
|
|
256
|
+
total_expenses: string;
|
|
257
|
+
net_income: string;
|
|
258
|
+
}
|
|
259
|
+
interface ProfitAndLoss {
|
|
260
|
+
start_date: string;
|
|
261
|
+
end_date: string;
|
|
262
|
+
currencies: ProfitAndLossCurrency[] | null;
|
|
263
|
+
}
|
|
264
|
+
interface BalanceSheetCurrency {
|
|
265
|
+
currency: string;
|
|
266
|
+
assets: StatementRow[] | null;
|
|
267
|
+
liabilities: StatementRow[] | null;
|
|
268
|
+
equity: StatementRow[] | null;
|
|
269
|
+
total_assets: string;
|
|
270
|
+
total_liabilities: string;
|
|
271
|
+
total_equity: string;
|
|
272
|
+
balanced: boolean;
|
|
273
|
+
}
|
|
274
|
+
interface BalanceSheet {
|
|
275
|
+
as_of: string;
|
|
276
|
+
currencies: BalanceSheetCurrency[] | null;
|
|
277
|
+
}
|
|
278
|
+
interface GeneralLedgerEntry {
|
|
279
|
+
transaction_id: string;
|
|
280
|
+
description: string;
|
|
281
|
+
reference?: string;
|
|
282
|
+
posted_at: string;
|
|
283
|
+
debit: string;
|
|
284
|
+
credit: string;
|
|
285
|
+
running_balance: string;
|
|
286
|
+
}
|
|
287
|
+
interface GeneralLedger {
|
|
288
|
+
account_id: string;
|
|
289
|
+
code: string;
|
|
290
|
+
name: string;
|
|
291
|
+
account_type: AccountType;
|
|
292
|
+
currency: string;
|
|
293
|
+
start_date: string;
|
|
294
|
+
end_date: string;
|
|
295
|
+
opening_balance: string;
|
|
296
|
+
entries: GeneralLedgerEntry[] | null;
|
|
297
|
+
closing_balance: string;
|
|
298
|
+
}
|
|
299
|
+
interface FxPosition {
|
|
300
|
+
currency: string;
|
|
301
|
+
assets: string;
|
|
302
|
+
liabilities: string;
|
|
303
|
+
net_position: string;
|
|
304
|
+
rate: string;
|
|
305
|
+
base_equivalent: string;
|
|
306
|
+
}
|
|
307
|
+
interface FxExposure {
|
|
308
|
+
as_of: string;
|
|
309
|
+
base_currency: string;
|
|
310
|
+
positions: FxPosition[] | null;
|
|
311
|
+
}
|
|
312
|
+
type RecurringFrequency = 'daily' | 'weekly' | 'monthly';
|
|
313
|
+
interface RecurringJournal {
|
|
314
|
+
id: string;
|
|
315
|
+
name: string;
|
|
316
|
+
description: string;
|
|
317
|
+
reference?: string;
|
|
318
|
+
frequency: RecurringFrequency;
|
|
319
|
+
next_run_on: string;
|
|
320
|
+
last_run_on?: string;
|
|
321
|
+
is_active: boolean;
|
|
322
|
+
entries: EntryLineInput[];
|
|
323
|
+
created_at: string;
|
|
324
|
+
}
|
|
325
|
+
interface CreateRecurringJournalInput {
|
|
326
|
+
name: string;
|
|
327
|
+
description: string;
|
|
328
|
+
reference?: string;
|
|
329
|
+
frequency: RecurringFrequency;
|
|
330
|
+
/** YYYY-MM-DD of the first posting */
|
|
331
|
+
starts_on: string;
|
|
332
|
+
entries: EntryLineInput[];
|
|
333
|
+
}
|
|
334
|
+
interface ListBalancesParams {
|
|
335
|
+
limit?: number;
|
|
336
|
+
offset?: number;
|
|
337
|
+
codePrefix?: string;
|
|
338
|
+
codeSuffix?: string;
|
|
339
|
+
currency?: string;
|
|
340
|
+
/** Account metadata containment filter, e.g. { org_id: '...' } */
|
|
341
|
+
metadata?: Record<string, string>;
|
|
342
|
+
}
|
|
343
|
+
interface BulkBalanceRow {
|
|
344
|
+
account_code: string;
|
|
345
|
+
currency: string;
|
|
346
|
+
balance: string;
|
|
347
|
+
version: number;
|
|
348
|
+
}
|
|
349
|
+
interface BalancesPage {
|
|
350
|
+
balances: BulkBalanceRow[];
|
|
351
|
+
total: number;
|
|
352
|
+
limit: number;
|
|
353
|
+
offset: number;
|
|
354
|
+
has_more: boolean;
|
|
355
|
+
}
|
|
356
|
+
interface LedgerEvent {
|
|
357
|
+
id: string;
|
|
358
|
+
sequence: number;
|
|
359
|
+
type: string;
|
|
360
|
+
aggregate_type: string;
|
|
361
|
+
aggregate_id: string;
|
|
362
|
+
data: unknown;
|
|
363
|
+
created_at: string;
|
|
364
|
+
}
|
|
365
|
+
interface EventsPage {
|
|
366
|
+
events: LedgerEvent[];
|
|
367
|
+
next_cursor: number;
|
|
368
|
+
has_more: boolean;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
declare class AccountsResource {
|
|
372
|
+
private readonly http;
|
|
373
|
+
constructor(http: HttpClient);
|
|
374
|
+
create(input: CreateAccountInput, options?: RequestOptions): Promise<Account>;
|
|
375
|
+
list(params?: ListAccountsParams, options?: RequestOptions): Promise<AccountsPage>;
|
|
376
|
+
get(accountId: string, options?: RequestOptions): Promise<Account>;
|
|
377
|
+
getByCode(code: string, options?: RequestOptions): Promise<Account>;
|
|
378
|
+
update(accountId: string, input: UpdateAccountInput, options?: RequestOptions): Promise<Account>;
|
|
379
|
+
deactivate(accountId: string, options?: RequestOptions): Promise<{
|
|
380
|
+
message: string;
|
|
381
|
+
}>;
|
|
382
|
+
/** Current materialized balance. Currency defaults to the tenant base currency. */
|
|
383
|
+
balance(accountId: string, options?: RequestOptions & {
|
|
384
|
+
currency?: string;
|
|
385
|
+
}): Promise<AccountBalance>;
|
|
386
|
+
/** Journal-derived balance through the end of a past day (YYYY-MM-DD, UTC). */
|
|
387
|
+
balanceAsOf(accountId: string, asOf: string, options?: RequestOptions & {
|
|
388
|
+
currency?: string;
|
|
389
|
+
}): Promise<AsOfBalance>;
|
|
390
|
+
hierarchy(options?: RequestOptions): Promise<Account[]>;
|
|
391
|
+
stats(options?: RequestOptions): Promise<AccountStats>;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
declare class BalancesResource {
|
|
395
|
+
private readonly http;
|
|
396
|
+
constructor(http: HttpClient);
|
|
397
|
+
/**
|
|
398
|
+
* Bulk balances: every (account, currency) row with its monotonic
|
|
399
|
+
* version. Filter by codePrefix/codeSuffix, currency, or account
|
|
400
|
+
* metadata containment (e.g. { org_id: '...' }).
|
|
401
|
+
*/
|
|
402
|
+
list(params?: ListBalancesParams, options?: RequestOptions): Promise<BalancesPage>;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
declare class EventsResource {
|
|
406
|
+
private readonly http;
|
|
407
|
+
constructor(http: HttpClient);
|
|
408
|
+
/**
|
|
409
|
+
* Durable event feed, strictly ordered by sequence. Poll with
|
|
410
|
+
* afterId = the last sequence you processed; store next_cursor.
|
|
411
|
+
*/
|
|
412
|
+
list(params?: {
|
|
413
|
+
afterId?: number;
|
|
414
|
+
limit?: number;
|
|
415
|
+
}, options?: RequestOptions): Promise<EventsPage>;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
declare class CurrenciesResource {
|
|
419
|
+
private readonly http;
|
|
420
|
+
constructor(http: HttpClient);
|
|
421
|
+
/**
|
|
422
|
+
* Register a currency with its precision policy. Postings beyond the
|
|
423
|
+
* exponent's decimal places are rejected. Unregistered currencies fall
|
|
424
|
+
* back to the storage maximum of 18 decimal places.
|
|
425
|
+
*/
|
|
426
|
+
register(input: RegisterCurrencyInput, options?: RequestOptions): Promise<Currency>;
|
|
427
|
+
list(options?: RequestOptions): Promise<Currency[]>;
|
|
428
|
+
update(code: string, input: UpdateCurrencyInput, options?: RequestOptions): Promise<Currency>;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
declare class PeriodsResource {
|
|
432
|
+
private readonly http;
|
|
433
|
+
constructor(http: HttpClient);
|
|
434
|
+
/** Periods of one tenant may not overlap; violations raise a 409. */
|
|
435
|
+
create(input: CreatePeriodInput, options?: RequestOptions): Promise<AccountingPeriod>;
|
|
436
|
+
list(options?: RequestOptions): Promise<AccountingPeriod[]>;
|
|
437
|
+
/**
|
|
438
|
+
* Close a period. Enforced by the database: nothing can post into a
|
|
439
|
+
* closed period, and posting attempts raise a 409.
|
|
440
|
+
*/
|
|
441
|
+
close(periodId: string, options?: RequestOptions): Promise<AccountingPeriod>;
|
|
442
|
+
reopen(periodId: string, options?: RequestOptions): Promise<AccountingPeriod>;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
declare class RecurringJournalsResource {
|
|
446
|
+
private readonly http;
|
|
447
|
+
constructor(http: HttpClient);
|
|
448
|
+
/**
|
|
449
|
+
* Register a repeating journal. Each occurrence posts exactly once: the
|
|
450
|
+
* worker derives the idempotency key from (schedule id, run date).
|
|
451
|
+
*/
|
|
452
|
+
create(input: CreateRecurringJournalInput, options?: RequestOptions): Promise<RecurringJournal>;
|
|
453
|
+
list(options?: RequestOptions): Promise<RecurringJournal[]>;
|
|
454
|
+
pause(scheduleId: string, options?: RequestOptions): Promise<RecurringJournal>;
|
|
455
|
+
resume(scheduleId: string, options?: RequestOptions): Promise<RecurringJournal>;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
declare class ReportsResource {
|
|
459
|
+
private readonly http;
|
|
460
|
+
constructor(http: HttpClient);
|
|
461
|
+
/**
|
|
462
|
+
* Trial balance derived from posted journal lines, grouped by currency.
|
|
463
|
+
* asOf (YYYY-MM-DD) means "through the end of that day, UTC"; defaults
|
|
464
|
+
* to now.
|
|
465
|
+
*/
|
|
466
|
+
trialBalance(options?: RequestOptions & {
|
|
467
|
+
asOf?: string;
|
|
468
|
+
}): Promise<TrialBalance>;
|
|
469
|
+
/** Revenue and expenses over an inclusive date range, optionally filtered by dimensions. */
|
|
470
|
+
profitAndLoss(options: RequestOptions & {
|
|
471
|
+
startDate: string;
|
|
472
|
+
endDate: string;
|
|
473
|
+
dimensions?: Record<string, string>;
|
|
474
|
+
}): Promise<ProfitAndLoss>;
|
|
475
|
+
/** Assets, liabilities, and equity (with computed retained earnings) as of a date. */
|
|
476
|
+
balanceSheet(options?: RequestOptions & {
|
|
477
|
+
asOf?: string;
|
|
478
|
+
}): Promise<BalanceSheet>;
|
|
479
|
+
/** One account's activity with opening, running, and closing balances. */
|
|
480
|
+
generalLedger(options: RequestOptions & {
|
|
481
|
+
accountCode: string;
|
|
482
|
+
startDate: string;
|
|
483
|
+
endDate: string;
|
|
484
|
+
currency?: string;
|
|
485
|
+
}): Promise<GeneralLedger>;
|
|
486
|
+
/** Per-currency net positions with base equivalents at the provided rates. */
|
|
487
|
+
fxExposure(options?: RequestOptions & {
|
|
488
|
+
rates?: Record<string, string>;
|
|
489
|
+
asOf?: string;
|
|
490
|
+
}): Promise<FxExposure>;
|
|
491
|
+
/**
|
|
492
|
+
* Posted journals as a Xero manual-journal import CSV (raw string).
|
|
493
|
+
* Dates are inclusive. Currency defaults to the tenant base currency.
|
|
494
|
+
*/
|
|
495
|
+
xeroJournalsCsv(options: RequestOptions & {
|
|
496
|
+
startDate: string;
|
|
497
|
+
endDate: string;
|
|
498
|
+
currency?: string;
|
|
499
|
+
}): Promise<string>;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
declare class TransactionsResource {
|
|
503
|
+
private readonly http;
|
|
504
|
+
constructor(http: HttpClient);
|
|
505
|
+
private idempotencyKey;
|
|
506
|
+
/**
|
|
507
|
+
* Post a balanced double-entry transaction. Debits must equal credits per
|
|
508
|
+
* currency or the API rejects with UNBALANCED_TRANSACTION. posted_at
|
|
509
|
+
* backdates the posting and requires the transactions:backdate scope.
|
|
510
|
+
*/
|
|
511
|
+
post(input: PostEntryInput, options?: RequestOptions): Promise<Transaction>;
|
|
512
|
+
get(transactionId: string, options?: RequestOptions & {
|
|
513
|
+
includeLines?: boolean;
|
|
514
|
+
}): Promise<Transaction>;
|
|
515
|
+
lines(transactionId: string, options?: RequestOptions): Promise<TransactionLine[]>;
|
|
516
|
+
list(params?: ListTransactionsParams, options?: RequestOptions): Promise<TransactionsPage>;
|
|
517
|
+
/**
|
|
518
|
+
* Maker-checker: store a fully validated entry with zero balance impact.
|
|
519
|
+
* Balances apply only when a DIFFERENT actor approves.
|
|
520
|
+
*/
|
|
521
|
+
draft(input: PostEntryInput, options?: RequestOptions): Promise<Transaction>;
|
|
522
|
+
/** Approve a draft (requires the transactions:approve scope and a different actor). */
|
|
523
|
+
approve(transactionId: string, options?: RequestOptions): Promise<Transaction>;
|
|
524
|
+
/** Reject a draft; it never had balance impact. */
|
|
525
|
+
reject(transactionId: string, options?: RequestOptions): Promise<Transaction>;
|
|
526
|
+
/** Append an immutable note (audit support). */
|
|
527
|
+
addNote(transactionId: string, note: string, options?: RequestOptions): Promise<TransactionNote>;
|
|
528
|
+
listNotes(transactionId: string, options?: RequestOptions): Promise<TransactionNote[]>;
|
|
529
|
+
/**
|
|
530
|
+
* Post a reversal: a new transaction mirroring the original with debits
|
|
531
|
+
* and credits swapped, linked via reverses_transaction_id. A transaction
|
|
532
|
+
* can be reversed at most once; a second attempt raises ALREADY_REVERSED.
|
|
533
|
+
*/
|
|
534
|
+
reverse(transactionId: string, reverseOptions?: {
|
|
535
|
+
idempotencyKey?: string;
|
|
536
|
+
description?: string;
|
|
537
|
+
metadata?: Record<string, unknown>;
|
|
538
|
+
}, options?: RequestOptions): Promise<Transaction>;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
/** Stable machine-readable error codes; branch on these, never on message text. */
|
|
542
|
+
type LedgerErrorCode = 'INSUFFICIENT_BALANCE' | 'UNBALANCED_TRANSACTION' | 'AMOUNT_PRECISION' | 'AMOUNT_TOO_LARGE' | 'CURRENCY_DEACTIVATED' | 'CURRENCY_PRECISION' | 'PERIOD_CLOSED' | 'ALREADY_REVERSED' | 'CANNOT_REVERSE_UNPOSTED' | 'ACCOUNT_NOT_FOUND' | 'ACCOUNT_EXISTS' | 'IDEMPOTENCY_CONFLICT' | 'VALIDATION_ERROR' | 'NOT_DRAFT' | 'SELF_APPROVAL' | 'TRANSACTION_NOT_FOUND' | (string & {});
|
|
543
|
+
/** Structured detail attached to INSUFFICIENT_BALANCE errors. */
|
|
544
|
+
interface InsufficientBalanceDetails {
|
|
545
|
+
account_code: string;
|
|
546
|
+
currency: string;
|
|
547
|
+
/** Decimal strings; render customer copy from these, never parse prose. */
|
|
548
|
+
attempted: string;
|
|
549
|
+
available: string;
|
|
550
|
+
}
|
|
551
|
+
/** Error raised for any non-success response from the ledger API. */
|
|
552
|
+
declare class LedgerApiError extends Error {
|
|
553
|
+
/** HTTP status code */
|
|
554
|
+
readonly status: number;
|
|
555
|
+
/** Alias for status, per the Alphaex integration contract. */
|
|
556
|
+
readonly httpStatus: number;
|
|
557
|
+
/** Stable machine-readable code (absent on transport-level failures). */
|
|
558
|
+
readonly code?: LedgerErrorCode;
|
|
559
|
+
/** Structured error context (e.g. InsufficientBalanceDetails). */
|
|
560
|
+
readonly details?: unknown;
|
|
561
|
+
/** Raw response body, when one could be read */
|
|
562
|
+
readonly body?: unknown;
|
|
563
|
+
constructor(status: number, message: string, options?: {
|
|
564
|
+
code?: string;
|
|
565
|
+
details?: unknown;
|
|
566
|
+
body?: unknown;
|
|
567
|
+
});
|
|
568
|
+
/** True for 409s: double reversals, closed periods, existing resources. */
|
|
569
|
+
get isConflict(): boolean;
|
|
570
|
+
/** Typed accessor for INSUFFICIENT_BALANCE detail. */
|
|
571
|
+
get insufficientBalance(): InsufficientBalanceDetails | undefined;
|
|
572
|
+
}
|
|
573
|
+
/** Thrown in strict idempotency mode when a mutating call omits the key. */
|
|
574
|
+
declare class MissingIdempotencyKeyError extends Error {
|
|
575
|
+
constructor(method: string);
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
declare class LedgerClient {
|
|
579
|
+
readonly accounts: AccountsResource;
|
|
580
|
+
readonly balances: BalancesResource;
|
|
581
|
+
readonly events: EventsResource;
|
|
582
|
+
readonly transactions: TransactionsResource;
|
|
583
|
+
readonly currencies: CurrenciesResource;
|
|
584
|
+
readonly periods: PeriodsResource;
|
|
585
|
+
readonly recurringJournals: RecurringJournalsResource;
|
|
586
|
+
readonly reports: ReportsResource;
|
|
587
|
+
constructor(options: LedgerClientOptions);
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
export { type Account, type AccountBalance, type AccountStats, type AccountType, type AccountingPeriod, type AccountsPage, type AsOfBalance, type BalanceSheet, type BalanceSheetCurrency, type BalancesPage, type BulkBalanceRow, type CreateAccountInput, type CreatePeriodInput, type CreateRecurringJournalInput, type Currency, type EntryLineInput, type EntrySide, type EventsPage, type FxExposure, type FxPosition, type GeneralLedger, type GeneralLedgerEntry, type InsufficientBalanceDetails, LedgerApiError, LedgerClient, type LedgerClientOptions, type LedgerErrorCode, type LedgerEvent, type ListAccountsParams, type ListBalancesParams, type ListTransactionsParams, MissingIdempotencyKeyError, type Pagination, type PeriodStatus, type PostEntryInput, type ProfitAndLoss, type ProfitAndLossCurrency, type RecurringFrequency, type RecurringJournal, type RegisterCurrencyInput, type RequestOptions, type StatementRow, type Transaction, type TransactionLine, type TransactionNote, type TransactionStatus, type TransactionsPage, type TrialBalance, type TrialBalanceCurrencyGroup, type TrialBalanceRow, type UpdateAccountInput, type UpdateCurrencyInput };
|