@robosystems/client 0.2.38 → 0.2.40

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.
@@ -0,0 +1,486 @@
1
+ 'use client'
2
+
3
+ /**
4
+ * Ledger Client for RoboSystems API
5
+ *
6
+ * High-level client for all ledger concerns: chart of accounts, transactions,
7
+ * trial balance, taxonomy, mappings, and AI auto-mapping. This is the
8
+ * operational backbone — reports consume these as inputs.
9
+ */
10
+
11
+ import {
12
+ autoMapElements,
13
+ createMappingAssociation,
14
+ createStructure,
15
+ deleteMappingAssociation,
16
+ getLedgerAccountTree,
17
+ getLedgerEntity,
18
+ getLedgerSummary,
19
+ getLedgerTransaction,
20
+ getLedgerTrialBalance,
21
+ getMappedTrialBalance,
22
+ getMappingCoverage,
23
+ getMappingDetail,
24
+ getReportingTaxonomy,
25
+ listElements,
26
+ listLedgerAccounts,
27
+ listLedgerTransactions,
28
+ listMappings,
29
+ listStructures,
30
+ } from '../sdk/sdk.gen'
31
+ import type {
32
+ AccountListResponse,
33
+ AccountTreeResponse,
34
+ LedgerSummaryResponse,
35
+ LedgerTransactionDetailResponse,
36
+ LedgerTransactionListResponse,
37
+ MappingCoverageResponse,
38
+ MappingDetailResponse,
39
+ TrialBalanceResponse,
40
+ } from '../sdk/types.gen'
41
+
42
+ // ── Friendly types ──────────────────────────────────────────────────────
43
+
44
+ export interface LedgerEntity {
45
+ id: string
46
+ name: string
47
+ legalName: string | null
48
+ entityType: string | null
49
+ industry: string | null
50
+ status: string | null
51
+ }
52
+
53
+ export interface MappingInfo {
54
+ id: string
55
+ name: string
56
+ description: string | null
57
+ structureType: string
58
+ taxonomyId: string
59
+ isActive: boolean
60
+ }
61
+
62
+ export interface MappingCoverage {
63
+ totalCoaElements: number
64
+ mappedCount: number
65
+ unmappedCount: number
66
+ coveragePercent: number
67
+ highConfidence: number
68
+ mediumConfidence: number
69
+ lowConfidence: number
70
+ }
71
+
72
+ export interface Structure {
73
+ id: string
74
+ name: string
75
+ structureType: string
76
+ }
77
+
78
+ // ── Client ──────────────────────────────────────────────────────────────
79
+
80
+ export class LedgerClient {
81
+ private config: {
82
+ baseUrl: string
83
+ credentials?: 'include' | 'same-origin' | 'omit'
84
+ headers?: Record<string, string>
85
+ token?: string
86
+ }
87
+
88
+ constructor(config: {
89
+ baseUrl: string
90
+ credentials?: 'include' | 'same-origin' | 'omit'
91
+ headers?: Record<string, string>
92
+ token?: string
93
+ }) {
94
+ this.config = config
95
+ }
96
+
97
+ // ── Entity ──────────────────────────────────────────────────────────
98
+
99
+ /**
100
+ * Get the entity (company/organization) for this graph.
101
+ */
102
+ async getEntity(graphId: string): Promise<LedgerEntity | null> {
103
+ const response = await getLedgerEntity({
104
+ path: { graph_id: graphId },
105
+ })
106
+
107
+ if (response.response.status === 404) return null
108
+ if (response.error) {
109
+ throw new Error(`Get entity failed: ${JSON.stringify(response.error)}`)
110
+ }
111
+
112
+ const data = response.data as Record<string, unknown>
113
+ return {
114
+ id: data.id as string,
115
+ name: data.name as string,
116
+ legalName: (data.legal_name as string) ?? null,
117
+ entityType: (data.entity_type as string) ?? null,
118
+ industry: (data.industry as string) ?? null,
119
+ status: (data.status as string) ?? null,
120
+ }
121
+ }
122
+
123
+ // ── Accounts (Chart of Accounts) ───────────────────────────────────
124
+
125
+ /**
126
+ * List accounts (flat).
127
+ */
128
+ async listAccounts(graphId: string): Promise<AccountListResponse> {
129
+ const response = await listLedgerAccounts({
130
+ path: { graph_id: graphId },
131
+ })
132
+
133
+ if (response.error) {
134
+ throw new Error(`List accounts failed: ${JSON.stringify(response.error)}`)
135
+ }
136
+
137
+ return response.data as AccountListResponse
138
+ }
139
+
140
+ /**
141
+ * Get the account tree (hierarchical).
142
+ */
143
+ async getAccountTree(graphId: string): Promise<AccountTreeResponse> {
144
+ const response = await getLedgerAccountTree({
145
+ path: { graph_id: graphId },
146
+ })
147
+
148
+ if (response.error) {
149
+ throw new Error(`Get account tree failed: ${JSON.stringify(response.error)}`)
150
+ }
151
+
152
+ return response.data as AccountTreeResponse
153
+ }
154
+
155
+ // ── Transactions ────────────────────────────────────────────────────
156
+
157
+ /**
158
+ * List transactions with optional date filters.
159
+ */
160
+ async listTransactions(
161
+ graphId: string,
162
+ options?: { startDate?: string; endDate?: string; limit?: number; offset?: number }
163
+ ): Promise<LedgerTransactionListResponse> {
164
+ const response = await listLedgerTransactions({
165
+ path: { graph_id: graphId },
166
+ query: {
167
+ start_date: options?.startDate,
168
+ end_date: options?.endDate,
169
+ limit: options?.limit,
170
+ offset: options?.offset,
171
+ },
172
+ })
173
+
174
+ if (response.error) {
175
+ throw new Error(`List transactions failed: ${JSON.stringify(response.error)}`)
176
+ }
177
+
178
+ return response.data as LedgerTransactionListResponse
179
+ }
180
+
181
+ /**
182
+ * Get transaction detail with entries and line items.
183
+ */
184
+ async getTransaction(
185
+ graphId: string,
186
+ transactionId: string
187
+ ): Promise<LedgerTransactionDetailResponse> {
188
+ const response = await getLedgerTransaction({
189
+ path: { graph_id: graphId, transaction_id: transactionId },
190
+ })
191
+
192
+ if (response.error) {
193
+ throw new Error(`Get transaction failed: ${JSON.stringify(response.error)}`)
194
+ }
195
+
196
+ return response.data as LedgerTransactionDetailResponse
197
+ }
198
+
199
+ // ── Trial Balance ──────────────────────────────────────────────────
200
+
201
+ /**
202
+ * Get trial balance (CoA-level debits/credits).
203
+ */
204
+ async getTrialBalance(
205
+ graphId: string,
206
+ options?: { startDate?: string; endDate?: string }
207
+ ): Promise<TrialBalanceResponse> {
208
+ const response = await getLedgerTrialBalance({
209
+ path: { graph_id: graphId },
210
+ query: {
211
+ start_date: options?.startDate,
212
+ end_date: options?.endDate,
213
+ },
214
+ })
215
+
216
+ if (response.error) {
217
+ throw new Error(`Get trial balance failed: ${JSON.stringify(response.error)}`)
218
+ }
219
+
220
+ return response.data as TrialBalanceResponse
221
+ }
222
+
223
+ /**
224
+ * Get mapped trial balance (CoA rolled up to GAAP concepts).
225
+ */
226
+ async getMappedTrialBalance(
227
+ graphId: string,
228
+ options?: { mappingId?: string; startDate?: string; endDate?: string }
229
+ ): Promise<unknown> {
230
+ const response = await getMappedTrialBalance({
231
+ path: { graph_id: graphId },
232
+ query: {
233
+ mapping_id: options?.mappingId,
234
+ start_date: options?.startDate,
235
+ end_date: options?.endDate,
236
+ },
237
+ })
238
+
239
+ if (response.error) {
240
+ throw new Error(`Get mapped trial balance failed: ${JSON.stringify(response.error)}`)
241
+ }
242
+
243
+ return response.data
244
+ }
245
+
246
+ // ── Summary ────────────────────────────────────────────────────────
247
+
248
+ /**
249
+ * Get ledger summary (account count, transaction count, date range).
250
+ */
251
+ async getSummary(graphId: string): Promise<LedgerSummaryResponse> {
252
+ const response = await getLedgerSummary({
253
+ path: { graph_id: graphId },
254
+ })
255
+
256
+ if (response.error) {
257
+ throw new Error(`Get summary failed: ${JSON.stringify(response.error)}`)
258
+ }
259
+
260
+ return response.data as LedgerSummaryResponse
261
+ }
262
+
263
+ // ── Taxonomy ────────────────────────────────────────────────────────
264
+
265
+ /**
266
+ * Get the reporting taxonomy (US GAAP seed).
267
+ */
268
+ async getReportingTaxonomy(graphId: string): Promise<unknown> {
269
+ const response = await getReportingTaxonomy({
270
+ path: { graph_id: graphId },
271
+ })
272
+
273
+ if (response.error) {
274
+ throw new Error(`Get reporting taxonomy failed: ${JSON.stringify(response.error)}`)
275
+ }
276
+
277
+ return response.data
278
+ }
279
+
280
+ /**
281
+ * List reporting structures (IS, BS, CF) for a taxonomy.
282
+ */
283
+ async listStructures(graphId: string, taxonomyId?: string): Promise<Structure[]> {
284
+ const response = await listStructures({
285
+ path: { graph_id: graphId },
286
+ query: taxonomyId ? { taxonomy_id: taxonomyId } : undefined,
287
+ })
288
+
289
+ if (response.error) {
290
+ throw new Error(`List structures failed: ${JSON.stringify(response.error)}`)
291
+ }
292
+
293
+ const data = response.data as { structures?: Array<Record<string, unknown>> }
294
+ return (data.structures ?? []).map((s) => ({
295
+ id: s.id as string,
296
+ name: s.name as string,
297
+ structureType: s.structure_type as string,
298
+ }))
299
+ }
300
+
301
+ /**
302
+ * List elements (CoA accounts, GAAP concepts, etc.).
303
+ */
304
+ async listElements(
305
+ graphId: string,
306
+ options?: {
307
+ taxonomyId?: string
308
+ source?: string
309
+ classification?: string
310
+ isAbstract?: boolean
311
+ limit?: number
312
+ offset?: number
313
+ }
314
+ ): Promise<unknown> {
315
+ const response = await listElements({
316
+ path: { graph_id: graphId },
317
+ query: {
318
+ taxonomy_id: options?.taxonomyId,
319
+ source: options?.source,
320
+ classification: options?.classification,
321
+ is_abstract: options?.isAbstract,
322
+ limit: options?.limit,
323
+ offset: options?.offset,
324
+ },
325
+ })
326
+
327
+ if (response.error) {
328
+ throw new Error(`List elements failed: ${JSON.stringify(response.error)}`)
329
+ }
330
+
331
+ return response.data
332
+ }
333
+
334
+ // ── Mappings ────────────────────────────────────────────────────────
335
+
336
+ /**
337
+ * Create a new CoA→GAAP mapping structure.
338
+ * Returns the created mapping info.
339
+ */
340
+ async createMappingStructure(
341
+ graphId: string,
342
+ options?: { name?: string; description?: string; taxonomyId?: string }
343
+ ): Promise<MappingInfo> {
344
+ const response = await createStructure({
345
+ path: { graph_id: graphId },
346
+ body: {
347
+ name: options?.name ?? 'CoA to Reporting',
348
+ description: options?.description ?? 'Map Chart of Accounts to US GAAP reporting concepts',
349
+ structure_type: 'coa_mapping',
350
+ taxonomy_id: options?.taxonomyId ?? 'tax_usgaap_reporting',
351
+ },
352
+ })
353
+
354
+ if (response.error) {
355
+ throw new Error(`Create mapping structure failed: ${JSON.stringify(response.error)}`)
356
+ }
357
+
358
+ const data = response.data as Record<string, unknown>
359
+ return {
360
+ id: data.id as string,
361
+ name: data.name as string,
362
+ description: (data.description as string) ?? null,
363
+ structureType: data.structure_type as string,
364
+ taxonomyId: data.taxonomy_id as string,
365
+ isActive: (data.is_active as boolean) ?? true,
366
+ }
367
+ }
368
+
369
+ /**
370
+ * List available CoA→GAAP mapping structures.
371
+ */
372
+ async listMappings(graphId: string): Promise<MappingInfo[]> {
373
+ const response = await listMappings({
374
+ path: { graph_id: graphId },
375
+ })
376
+
377
+ if (response.error) {
378
+ throw new Error(`List mappings failed: ${JSON.stringify(response.error)}`)
379
+ }
380
+
381
+ const data = response.data as { structures?: Array<Record<string, unknown>> }
382
+ return (data.structures ?? []).map((s) => ({
383
+ id: s.id as string,
384
+ name: s.name as string,
385
+ description: (s.description as string) ?? null,
386
+ structureType: s.structure_type as string,
387
+ taxonomyId: s.taxonomy_id as string,
388
+ isActive: (s.is_active as boolean) ?? true,
389
+ }))
390
+ }
391
+
392
+ /**
393
+ * Get mapping detail — all associations with element names.
394
+ */
395
+ async getMappingDetail(graphId: string, mappingId: string): Promise<MappingDetailResponse> {
396
+ const response = await getMappingDetail({
397
+ path: { graph_id: graphId, mapping_id: mappingId },
398
+ })
399
+
400
+ if (response.error) {
401
+ throw new Error(`Get mapping detail failed: ${JSON.stringify(response.error)}`)
402
+ }
403
+
404
+ return response.data as MappingDetailResponse
405
+ }
406
+
407
+ /**
408
+ * Get mapping coverage — how many CoA elements are mapped.
409
+ */
410
+ async getMappingCoverage(graphId: string, mappingId: string): Promise<MappingCoverage> {
411
+ const response = await getMappingCoverage({
412
+ path: { graph_id: graphId, mapping_id: mappingId },
413
+ })
414
+
415
+ if (response.error) {
416
+ throw new Error(`Get mapping coverage failed: ${JSON.stringify(response.error)}`)
417
+ }
418
+
419
+ const data = response.data as MappingCoverageResponse
420
+ return {
421
+ totalCoaElements: data.total_coa_elements ?? 0,
422
+ mappedCount: data.mapped_count ?? 0,
423
+ unmappedCount: data.unmapped_count ?? 0,
424
+ coveragePercent: data.coverage_percent ?? 0,
425
+ highConfidence: data.high_confidence ?? 0,
426
+ mediumConfidence: data.medium_confidence ?? 0,
427
+ lowConfidence: data.low_confidence ?? 0,
428
+ }
429
+ }
430
+
431
+ /**
432
+ * Create a manual mapping association (CoA element → GAAP element).
433
+ */
434
+ async createMapping(
435
+ graphId: string,
436
+ mappingId: string,
437
+ fromElementId: string,
438
+ toElementId: string,
439
+ confidence?: number
440
+ ): Promise<void> {
441
+ const response = await createMappingAssociation({
442
+ path: { graph_id: graphId, mapping_id: mappingId },
443
+ body: {
444
+ from_element_id: fromElementId,
445
+ to_element_id: toElementId,
446
+ confidence: confidence ?? 1.0,
447
+ },
448
+ })
449
+
450
+ if (response.error) {
451
+ throw new Error(`Create mapping failed: ${JSON.stringify(response.error)}`)
452
+ }
453
+ }
454
+
455
+ /**
456
+ * Delete a mapping association.
457
+ */
458
+ async deleteMapping(graphId: string, mappingId: string, associationId: string): Promise<void> {
459
+ const response = await deleteMappingAssociation({
460
+ path: { graph_id: graphId, mapping_id: mappingId, association_id: associationId },
461
+ })
462
+
463
+ if (response.error) {
464
+ throw new Error(`Delete mapping failed: ${JSON.stringify(response.error)}`)
465
+ }
466
+ }
467
+
468
+ /**
469
+ * Trigger AI auto-mapping (MappingAgent).
470
+ * Returns immediately — the agent runs in the background.
471
+ */
472
+ async autoMap(graphId: string, mappingId: string): Promise<{ operationId?: string }> {
473
+ const response = await autoMapElements({
474
+ path: { graph_id: graphId, mapping_id: mappingId },
475
+ })
476
+
477
+ if (response.error) {
478
+ throw new Error(`Auto-map failed: ${JSON.stringify(response.error)}`)
479
+ }
480
+
481
+ const data = response.data as Record<string, unknown> | undefined
482
+ return {
483
+ operationId: data?.operation_id as string | undefined,
484
+ }
485
+ }
486
+ }
@@ -0,0 +1,109 @@
1
+ export interface Report {
2
+ id: string;
3
+ name: string;
4
+ taxonomyId: string;
5
+ generationStatus: string;
6
+ periodType: string;
7
+ periodStart: string | null;
8
+ periodEnd: string | null;
9
+ comparative: boolean;
10
+ mappingId: string | null;
11
+ aiGenerated: boolean;
12
+ createdAt: string;
13
+ lastGenerated: string | null;
14
+ structures: Structure[];
15
+ /** Non-null when this report was shared from another graph */
16
+ sourceGraphId: string | null;
17
+ sourceReportId: string | null;
18
+ sharedAt: string | null;
19
+ }
20
+ import type { Structure } from './LedgerClient';
21
+ export type { Structure } from './LedgerClient';
22
+ export interface StatementRow {
23
+ elementId: string;
24
+ elementQname: string;
25
+ elementName: string;
26
+ classification: string;
27
+ currentValue: number;
28
+ priorValue: number | null;
29
+ isSubtotal: boolean;
30
+ depth: number;
31
+ }
32
+ export interface StatementData {
33
+ reportId: string;
34
+ structureId: string;
35
+ structureName: string;
36
+ structureType: string;
37
+ periodStart: string;
38
+ periodEnd: string;
39
+ comparativePeriodStart: string | null;
40
+ comparativePeriodEnd: string | null;
41
+ rows: StatementRow[];
42
+ validation: {
43
+ passed: boolean;
44
+ checks: string[];
45
+ failures: string[];
46
+ warnings: string[];
47
+ } | null;
48
+ unmappedCount: number;
49
+ }
50
+ export interface ShareResult {
51
+ reportId: string;
52
+ results: Array<{
53
+ targetGraphId: string;
54
+ status: 'shared' | 'error';
55
+ error: string | null;
56
+ factCount: number;
57
+ }>;
58
+ }
59
+ export interface CreateReportOptions {
60
+ name: string;
61
+ mappingId: string;
62
+ periodStart: string;
63
+ periodEnd: string;
64
+ taxonomyId?: string;
65
+ periodType?: string;
66
+ comparative?: boolean;
67
+ }
68
+ export declare class ReportClient {
69
+ private config;
70
+ constructor(config: {
71
+ baseUrl: string;
72
+ credentials?: 'include' | 'same-origin' | 'omit';
73
+ headers?: Record<string, string>;
74
+ token?: string;
75
+ });
76
+ /**
77
+ * Create a report — generates facts for all structures in the taxonomy.
78
+ */
79
+ create(graphId: string, options: CreateReportOptions): Promise<Report>;
80
+ /**
81
+ * List all reports for a graph (includes received shared reports).
82
+ */
83
+ list(graphId: string): Promise<Report[]>;
84
+ /**
85
+ * Get a report with its available structures.
86
+ */
87
+ get(graphId: string, reportId: string): Promise<Report>;
88
+ /**
89
+ * Render a financial statement — facts viewed through a structure.
90
+ *
91
+ * @param structureType - income_statement, balance_sheet, cash_flow_statement
92
+ */
93
+ statement(graphId: string, reportId: string, structureType: string): Promise<StatementData>;
94
+ /**
95
+ * Regenerate a report with new period dates.
96
+ */
97
+ regenerate(graphId: string, reportId: string, periodStart: string, periodEnd: string): Promise<Report>;
98
+ /**
99
+ * Delete a report and its generated facts.
100
+ */
101
+ delete(graphId: string, reportId: string): Promise<void>;
102
+ /**
103
+ * Share a published report to other graphs (snapshot copy).
104
+ */
105
+ share(graphId: string, reportId: string, targetGraphIds: string[]): Promise<ShareResult>;
106
+ /** Check if a report was received via sharing (vs locally created). */
107
+ isSharedReport(report: Report): boolean;
108
+ private _toReport;
109
+ }