@robosystems/client 0.2.48 → 0.3.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 (190) hide show
  1. package/extensions/InvestorClient.d.ts +91 -0
  2. package/extensions/InvestorClient.js +223 -0
  3. package/extensions/InvestorClient.ts +501 -0
  4. package/extensions/LedgerClient.d.ts +213 -165
  5. package/extensions/LedgerClient.js +315 -393
  6. package/extensions/LedgerClient.ts +887 -564
  7. package/extensions/ReportClient.d.ts +77 -115
  8. package/extensions/ReportClient.js +124 -211
  9. package/extensions/ReportClient.ts +298 -358
  10. package/extensions/config.js +1 -1
  11. package/extensions/config.ts +1 -1
  12. package/extensions/graphql/client.d.ts +46 -0
  13. package/extensions/graphql/client.js +75 -0
  14. package/extensions/graphql/client.ts +82 -0
  15. package/extensions/graphql/generated/graphql.d.ts +1786 -0
  16. package/extensions/graphql/generated/graphql.js +2671 -0
  17. package/extensions/graphql/generated/graphql.ts +4491 -0
  18. package/extensions/graphql/queries/investor/holdings.d.ts +8 -0
  19. package/extensions/graphql/queries/investor/holdings.js +36 -0
  20. package/extensions/graphql/queries/investor/holdings.ts +34 -0
  21. package/extensions/graphql/queries/investor/portfolio.d.ts +4 -0
  22. package/extensions/graphql/queries/investor/portfolio.js +21 -0
  23. package/extensions/graphql/queries/investor/portfolio.ts +19 -0
  24. package/extensions/graphql/queries/investor/portfolios.d.ts +4 -0
  25. package/extensions/graphql/queries/investor/portfolios.js +29 -0
  26. package/extensions/graphql/queries/investor/portfolios.ts +27 -0
  27. package/extensions/graphql/queries/investor/position.d.ts +4 -0
  28. package/extensions/graphql/queries/investor/position.js +33 -0
  29. package/extensions/graphql/queries/investor/position.ts +31 -0
  30. package/extensions/graphql/queries/investor/positions.d.ts +8 -0
  31. package/extensions/graphql/queries/investor/positions.js +57 -0
  32. package/extensions/graphql/queries/investor/positions.ts +55 -0
  33. package/extensions/graphql/queries/investor/securities.d.ts +8 -0
  34. package/extensions/graphql/queries/investor/securities.js +50 -0
  35. package/extensions/graphql/queries/investor/securities.ts +48 -0
  36. package/extensions/graphql/queries/investor/security.d.ts +4 -0
  37. package/extensions/graphql/queries/investor/security.js +26 -0
  38. package/extensions/graphql/queries/investor/security.ts +24 -0
  39. package/extensions/graphql/queries/ledger/accountRollups.d.ts +7 -0
  40. package/extensions/graphql/queries/ledger/accountRollups.js +36 -0
  41. package/extensions/graphql/queries/ledger/accountRollups.ts +34 -0
  42. package/extensions/graphql/queries/ledger/accountTree.d.ts +11 -0
  43. package/extensions/graphql/queries/ledger/accountTree.js +61 -0
  44. package/extensions/graphql/queries/ledger/accountTree.ts +59 -0
  45. package/extensions/graphql/queries/ledger/accounts.d.ts +8 -0
  46. package/extensions/graphql/queries/ledger/accounts.js +45 -0
  47. package/extensions/graphql/queries/ledger/accounts.ts +43 -0
  48. package/extensions/graphql/queries/ledger/closingBookStructures.d.ts +6 -0
  49. package/extensions/graphql/queries/ledger/closingBookStructures.js +27 -0
  50. package/extensions/graphql/queries/ledger/closingBookStructures.ts +25 -0
  51. package/extensions/graphql/queries/ledger/elements.d.ts +6 -0
  52. package/extensions/graphql/queries/ledger/elements.js +56 -0
  53. package/extensions/graphql/queries/ledger/elements.ts +54 -0
  54. package/extensions/graphql/queries/ledger/entities.d.ts +7 -0
  55. package/extensions/graphql/queries/ledger/entities.js +31 -0
  56. package/extensions/graphql/queries/ledger/entities.ts +29 -0
  57. package/extensions/graphql/queries/ledger/entity.d.ts +14 -0
  58. package/extensions/graphql/queries/ledger/entity.js +55 -0
  59. package/extensions/graphql/queries/ledger/entity.ts +54 -0
  60. package/extensions/graphql/queries/ledger/fiscalCalendar.d.ts +8 -0
  61. package/extensions/graphql/queries/ledger/fiscalCalendar.js +35 -0
  62. package/extensions/graphql/queries/ledger/fiscalCalendar.ts +33 -0
  63. package/extensions/graphql/queries/ledger/mappedTrialBalance.d.ts +9 -0
  64. package/extensions/graphql/queries/ledger/mappedTrialBalance.js +29 -0
  65. package/extensions/graphql/queries/ledger/mappedTrialBalance.ts +27 -0
  66. package/extensions/graphql/queries/ledger/mapping.d.ts +5 -0
  67. package/extensions/graphql/queries/ledger/mapping.js +35 -0
  68. package/extensions/graphql/queries/ledger/mapping.ts +33 -0
  69. package/extensions/graphql/queries/ledger/mappingCoverage.d.ts +5 -0
  70. package/extensions/graphql/queries/ledger/mappingCoverage.js +22 -0
  71. package/extensions/graphql/queries/ledger/mappingCoverage.ts +20 -0
  72. package/extensions/graphql/queries/ledger/mappings.d.ts +6 -0
  73. package/extensions/graphql/queries/ledger/mappings.js +23 -0
  74. package/extensions/graphql/queries/ledger/mappings.ts +21 -0
  75. package/extensions/graphql/queries/ledger/periodCloseStatus.d.ts +6 -0
  76. package/extensions/graphql/queries/ledger/periodCloseStatus.js +29 -0
  77. package/extensions/graphql/queries/ledger/periodCloseStatus.ts +27 -0
  78. package/extensions/graphql/queries/ledger/periodDrafts.d.ts +8 -0
  79. package/extensions/graphql/queries/ledger/periodDrafts.js +45 -0
  80. package/extensions/graphql/queries/ledger/periodDrafts.ts +43 -0
  81. package/extensions/graphql/queries/ledger/publishList.d.ts +5 -0
  82. package/extensions/graphql/queries/ledger/publishList.js +29 -0
  83. package/extensions/graphql/queries/ledger/publishList.ts +27 -0
  84. package/extensions/graphql/queries/ledger/publishLists.d.ts +5 -0
  85. package/extensions/graphql/queries/ledger/publishLists.js +29 -0
  86. package/extensions/graphql/queries/ledger/publishLists.ts +27 -0
  87. package/extensions/graphql/queries/ledger/report.d.ts +5 -0
  88. package/extensions/graphql/queries/ledger/report.js +40 -0
  89. package/extensions/graphql/queries/ledger/report.ts +38 -0
  90. package/extensions/graphql/queries/ledger/reportingTaxonomy.d.ts +6 -0
  91. package/extensions/graphql/queries/ledger/reportingTaxonomy.js +27 -0
  92. package/extensions/graphql/queries/ledger/reportingTaxonomy.ts +25 -0
  93. package/extensions/graphql/queries/ledger/reports.d.ts +8 -0
  94. package/extensions/graphql/queries/ledger/reports.js +45 -0
  95. package/extensions/graphql/queries/ledger/reports.ts +43 -0
  96. package/extensions/graphql/queries/ledger/scheduleFacts.d.ts +7 -0
  97. package/extensions/graphql/queries/ledger/scheduleFacts.js +24 -0
  98. package/extensions/graphql/queries/ledger/scheduleFacts.ts +22 -0
  99. package/extensions/graphql/queries/ledger/schedules.d.ts +6 -0
  100. package/extensions/graphql/queries/ledger/schedules.js +24 -0
  101. package/extensions/graphql/queries/ledger/schedules.ts +22 -0
  102. package/extensions/graphql/queries/ledger/statement.d.ts +9 -0
  103. package/extensions/graphql/queries/ledger/statement.js +43 -0
  104. package/extensions/graphql/queries/ledger/statement.ts +41 -0
  105. package/extensions/graphql/queries/ledger/structures.d.ts +5 -0
  106. package/extensions/graphql/queries/ledger/structures.js +22 -0
  107. package/extensions/graphql/queries/ledger/structures.ts +20 -0
  108. package/extensions/graphql/queries/ledger/summary.d.ts +7 -0
  109. package/extensions/graphql/queries/ledger/summary.js +25 -0
  110. package/extensions/graphql/queries/ledger/summary.ts +23 -0
  111. package/extensions/graphql/queries/ledger/taxonomies.d.ts +5 -0
  112. package/extensions/graphql/queries/ledger/taxonomies.js +28 -0
  113. package/extensions/graphql/queries/ledger/taxonomies.ts +26 -0
  114. package/extensions/graphql/queries/ledger/transaction.d.ts +6 -0
  115. package/extensions/graphql/queries/ledger/transaction.js +49 -0
  116. package/extensions/graphql/queries/ledger/transaction.ts +47 -0
  117. package/extensions/graphql/queries/ledger/transactions.d.ts +7 -0
  118. package/extensions/graphql/queries/ledger/transactions.js +49 -0
  119. package/extensions/graphql/queries/ledger/transactions.ts +47 -0
  120. package/extensions/graphql/queries/ledger/trialBalance.d.ts +7 -0
  121. package/extensions/graphql/queries/ledger/trialBalance.js +28 -0
  122. package/extensions/graphql/queries/ledger/trialBalance.ts +26 -0
  123. package/extensions/graphql/queries/ledger/unmappedElements.d.ts +8 -0
  124. package/extensions/graphql/queries/ledger/unmappedElements.js +29 -0
  125. package/extensions/graphql/queries/ledger/unmappedElements.ts +27 -0
  126. package/extensions/hooks.d.ts +1 -1
  127. package/extensions/index.d.ts +5 -1
  128. package/extensions/index.js +13 -1
  129. package/extensions/index.ts +14 -0
  130. package/index.ts +2 -2
  131. package/package.json +14 -5
  132. package/sdk/index.d.ts +2 -2
  133. package/sdk/index.js +38 -65
  134. package/sdk/index.ts +2 -2
  135. package/sdk/sdk.gen.d.ts +101 -220
  136. package/sdk/sdk.gen.js +251 -445
  137. package/sdk/sdk.gen.ts +216 -409
  138. package/sdk/types.gen.d.ts +4586 -7045
  139. package/sdk/types.gen.ts +4702 -7334
  140. package/sdk.gen.d.ts +101 -220
  141. package/sdk.gen.js +251 -445
  142. package/sdk.gen.ts +216 -409
  143. package/types.gen.d.ts +4586 -7045
  144. package/types.gen.ts +4702 -7334
  145. package/extensions/AgentClient.test.ts +0 -403
  146. package/extensions/LedgerClient.test.ts +0 -1138
  147. package/extensions/OperationClient.test.ts +0 -365
  148. package/extensions/QueryClient.test.ts +0 -432
  149. package/extensions/ReportClient.test.ts +0 -828
  150. package/extensions/SSEClient.test.ts +0 -375
  151. package/extensions/config.test.ts +0 -199
  152. package/extensions/hooks.test.ts +0 -373
  153. package/extensions/index.test.ts +0 -420
  154. package/sdk-extensions/AgentClient.d.ts +0 -82
  155. package/sdk-extensions/AgentClient.js +0 -218
  156. package/sdk-extensions/AgentClient.test.ts +0 -403
  157. package/sdk-extensions/AgentClient.ts +0 -321
  158. package/sdk-extensions/LedgerClient.d.ts +0 -242
  159. package/sdk-extensions/LedgerClient.js +0 -496
  160. package/sdk-extensions/LedgerClient.test.ts +0 -1138
  161. package/sdk-extensions/LedgerClient.ts +0 -800
  162. package/sdk-extensions/OperationClient.d.ts +0 -65
  163. package/sdk-extensions/OperationClient.js +0 -251
  164. package/sdk-extensions/OperationClient.test.ts +0 -365
  165. package/sdk-extensions/OperationClient.ts +0 -324
  166. package/sdk-extensions/QueryClient.d.ts +0 -52
  167. package/sdk-extensions/QueryClient.js +0 -313
  168. package/sdk-extensions/QueryClient.test.ts +0 -432
  169. package/sdk-extensions/QueryClient.ts +0 -420
  170. package/sdk-extensions/README.md +0 -901
  171. package/sdk-extensions/ReportClient.d.ts +0 -151
  172. package/sdk-extensions/ReportClient.js +0 -278
  173. package/sdk-extensions/ReportClient.test.ts +0 -828
  174. package/sdk-extensions/ReportClient.ts +0 -486
  175. package/sdk-extensions/SSEClient.d.ts +0 -62
  176. package/sdk-extensions/SSEClient.js +0 -154
  177. package/sdk-extensions/SSEClient.test.ts +0 -375
  178. package/sdk-extensions/SSEClient.ts +0 -210
  179. package/sdk-extensions/config.d.ts +0 -57
  180. package/sdk-extensions/config.js +0 -152
  181. package/sdk-extensions/config.test.ts +0 -199
  182. package/sdk-extensions/config.ts +0 -175
  183. package/sdk-extensions/hooks.d.ts +0 -110
  184. package/sdk-extensions/hooks.js +0 -384
  185. package/sdk-extensions/hooks.test.ts +0 -373
  186. package/sdk-extensions/hooks.ts +0 -459
  187. package/sdk-extensions/index.d.ts +0 -63
  188. package/sdk-extensions/index.js +0 -164
  189. package/sdk-extensions/index.test.ts +0 -420
  190. package/sdk-extensions/index.ts +0 -203
@@ -3,135 +3,74 @@
3
3
  /**
4
4
  * Report Client for RoboSystems API
5
5
  *
6
- * High-level client for report lifecycle: create, list, view statements,
7
- * regenerate, share, and delete. Reports consume ledger data (mappings,
8
- * trial balance) as inputs use LedgerClient for those concerns.
6
+ * High-level facade for the report + publish-list surface:
7
+ * create/list/view/regenerate/share/delete reports, render financial
8
+ * statements, and manage publish lists (distribution lists for shared
9
+ * reports). Reports consume ledger data (mappings, trial balance) as
10
+ * inputs — use `LedgerClient` for those concerns.
11
+ *
12
+ * **Transport split:**
13
+ * - **Reads** (listReports, getReport, getStatement, listPublishLists,
14
+ * getPublishList) go through GraphQL at
15
+ * `/extensions/{graph_id}/graphql`.
16
+ * - **Writes** (createReport, regenerateReport, deleteReport, shareReport,
17
+ * and the publish-list CRUD) go through named operations at
18
+ * `/extensions/roboledger/{graph_id}/operations/{operation_name}`.
19
+ *
20
+ * Every write returns an `OperationEnvelope`; this facade unwraps
21
+ * `envelope.result` for sync commands, or returns `{ operationId, status }`
22
+ * for async dispatches (createReport, regenerateReport, shareReport).
9
23
  */
10
24
 
25
+ import type { TypedDocumentNode } from '@graphql-typed-document-node/core'
26
+ import { ClientError } from 'graphql-request'
11
27
  import {
12
- addPublishListMembers,
13
- createPublishList,
14
- createReport,
15
- deletePublishList,
16
- deleteReport,
17
- getPublishList,
18
- getReport,
19
- getStatement,
20
- listPublishLists,
21
- listReports,
22
- regenerateReport,
23
- removePublishListMember,
24
- shareReport,
25
- updatePublishList,
28
+ opAddPublishListMembers,
29
+ opCreatePublishList,
30
+ opCreateReport,
31
+ opDeletePublishList,
32
+ opDeleteReport,
33
+ opRegenerateReport,
34
+ opRemovePublishListMember,
35
+ opShareReport,
36
+ opUpdatePublishList,
26
37
  } from '../sdk.gen'
27
38
  import type {
39
+ AddPublishListMembersOperation,
40
+ CreatePublishListRequest,
28
41
  CreateReportRequest,
29
- FactRowResponse,
30
- PublishListDetailResponse,
31
- PublishListListResponse,
32
- PublishListMemberResponse,
33
- PublishListResponse,
34
- RegenerateReportRequest,
35
- ReportListResponse,
36
- ReportResponse,
37
- ShareReportResponse,
38
- StatementResponse,
39
- StructureSummary,
40
- ValidationCheckResponse,
42
+ OperationEnvelope,
43
+ UpdatePublishListOperation,
41
44
  } from '../types.gen'
42
-
43
- // ── Friendly types ──────────────────────────────────────────────────────
44
-
45
- export interface Report {
46
- id: string
47
- name: string
48
- taxonomyId: string
49
- generationStatus: string
50
- periodType: string
51
- periodStart: string | null
52
- periodEnd: string | null
53
- comparative: boolean
54
- mappingId: string | null
55
- aiGenerated: boolean
56
- createdAt: string
57
- lastGenerated: string | null
58
- structures: Structure[]
59
- /** Entity name (source company for shared reports, own entity for native) */
60
- entityName: string | null
61
- /** Non-null when this report was shared from another graph */
62
- sourceGraphId: string | null
63
- sourceReportId: string | null
64
- sharedAt: string | null
65
- }
66
-
67
- // Structure type re-exported from LedgerClient
68
- import type { Structure } from './LedgerClient'
69
- export type { Structure } from './LedgerClient'
70
-
71
- export interface StatementPeriod {
72
- start: string
73
- end: string
74
- label: string
75
- }
76
-
77
- export interface StatementRow {
78
- elementId: string
79
- elementQname: string
80
- elementName: string
81
- classification: string
82
- values: (number | null)[]
83
- isSubtotal: boolean
84
- depth: number
85
- }
86
-
87
- export interface StatementData {
88
- reportId: string
89
- structureId: string
90
- structureName: string
91
- structureType: string
92
- periods: StatementPeriod[]
93
- rows: StatementRow[]
94
- validation: {
95
- passed: boolean
96
- checks: string[]
97
- failures: string[]
98
- warnings: string[]
99
- } | null
100
- unmappedCount: number
101
- }
102
-
103
- export interface ShareResult {
104
- reportId: string
105
- results: Array<{
106
- targetGraphId: string
107
- status: 'shared' | 'error'
108
- error: string | null
109
- factCount: number
110
- }>
111
- }
112
-
113
- export interface PublishList {
114
- id: string
115
- name: string
116
- description: string | null
117
- memberCount: number
118
- createdBy: string
119
- createdAt: string
120
- updatedAt: string
121
- }
122
-
123
- export interface PublishListDetail extends PublishList {
124
- members: PublishListMember[]
125
- }
126
-
127
- export interface PublishListMember {
128
- id: string
129
- targetGraphId: string
130
- targetGraphName: string | null
131
- targetOrgName: string | null
132
- addedBy: string
133
- addedAt: string
134
- }
45
+ import { GraphQLClientCache } from './graphql/client'
46
+ import {
47
+ GetLedgerPublishListDocument,
48
+ GetLedgerReportDocument,
49
+ GetLedgerStatementDocument,
50
+ ListLedgerPublishListsDocument,
51
+ ListLedgerReportsDocument,
52
+ type GetLedgerPublishListQuery,
53
+ type GetLedgerReportQuery,
54
+ type GetLedgerStatementQuery,
55
+ type ListLedgerPublishListsQuery,
56
+ type ListLedgerReportsQuery,
57
+ } from './graphql/generated/graphql'
58
+
59
+ // ── Types derived from GraphQL codegen ──────────────────────────────────
60
+
61
+ export type Report = NonNullable<GetLedgerReportQuery['report']>
62
+ export type ReportListItem = NonNullable<ListLedgerReportsQuery['reports']>['reports'][number]
63
+ export type StatementData = NonNullable<GetLedgerStatementQuery['statement']>
64
+ export type StatementPeriod = StatementData['periods'][number]
65
+ export type StatementRow = StatementData['rows'][number]
66
+
67
+ export type PublishList = NonNullable<
68
+ ListLedgerPublishListsQuery['publishLists']
69
+ >['publishLists'][number]
70
+ export type PublishListDetail = NonNullable<GetLedgerPublishListQuery['publishList']>
71
+ export type PublishListMember = PublishListDetail['members'][number]
72
+
73
+ // ── Caller-facing option interfaces ─────────────────────────────────────
135
74
 
136
75
  export interface PeriodSpecInput {
137
76
  start: string
@@ -151,29 +90,54 @@ export interface CreateReportOptions {
151
90
  periods?: PeriodSpecInput[]
152
91
  }
153
92
 
93
+ /**
94
+ * Envelope around a report operation. `status === "completed"` means the
95
+ * backend produced the report synchronously — `result` contains the
96
+ * freshly-created report shape (same fields as `ReportListItem`), so
97
+ * consumers can read `result?.id` immediately. For pending/failed
98
+ * dispatches, `result` is null and consumers should subscribe to
99
+ * `/v1/operations/{operationId}/stream` for progress.
100
+ *
101
+ * The loose `{ id; name; ... }` shape here intentionally mirrors the
102
+ * GraphQL `report` field without pulling in every nullable child relation
103
+ * — `create_report` and `regenerate_report` return a freshly-generated
104
+ * row, not a fully-resolved GraphQL projection.
105
+ */
106
+ export interface ReportOperationAck {
107
+ operationId: string
108
+ status: OperationEnvelope['status']
109
+ /**
110
+ * Synchronous command result. Populated for `status === "completed"`
111
+ * dispatches where the backend produced the report inline.
112
+ */
113
+ result: Record<string, unknown> | null
114
+ }
115
+
154
116
  // ── Client ──────────────────────────────────────────────────────────────
155
117
 
118
+ interface ReportClientConfig {
119
+ baseUrl: string
120
+ credentials?: 'include' | 'same-origin' | 'omit'
121
+ headers?: Record<string, string>
122
+ token?: string
123
+ }
124
+
156
125
  export class ReportClient {
157
- private config: {
158
- baseUrl: string
159
- credentials?: 'include' | 'same-origin' | 'omit'
160
- headers?: Record<string, string>
161
- token?: string
162
- }
126
+ private config: ReportClientConfig
127
+ private gql: GraphQLClientCache
163
128
 
164
- constructor(config: {
165
- baseUrl: string
166
- credentials?: 'include' | 'same-origin' | 'omit'
167
- headers?: Record<string, string>
168
- token?: string
169
- }) {
129
+ constructor(config: ReportClientConfig) {
170
130
  this.config = config
131
+ this.gql = new GraphQLClientCache(config)
171
132
  }
172
133
 
134
+ // ── Reports ─────────────────────────────────────────────────────────
135
+
173
136
  /**
174
- * Create a report generates facts for all structures in the taxonomy.
137
+ * Kick off report creation (async). Use the returned `operationId` to
138
+ * subscribe to progress via SSE, then call `get()` once finished.
175
139
  */
176
- async create(graphId: string, options: CreateReportOptions): Promise<Report> {
140
+ async create(graphId: string, options: CreateReportOptions): Promise<ReportOperationAck> {
177
141
  const body: CreateReportRequest = {
178
142
  name: options.name,
179
143
  mapping_id: options.mappingId,
@@ -183,52 +147,41 @@ export class ReportClient {
183
147
  period_type: options.periodType ?? 'quarterly',
184
148
  comparative: options.comparative ?? true,
185
149
  }
186
-
187
150
  if (options.periods && options.periods.length > 0) {
188
151
  body.periods = options.periods
189
152
  }
190
-
191
- const response = await createReport({
192
- path: { graph_id: graphId },
193
- body,
194
- })
195
-
196
- if (response.error) {
197
- throw new Error(`Create report failed: ${JSON.stringify(response.error)}`)
153
+ const envelope = await this.callOperation(
154
+ 'Create report',
155
+ opCreateReport({ path: { graph_id: graphId }, body })
156
+ )
157
+ return {
158
+ operationId: envelope.operationId,
159
+ status: envelope.status,
160
+ result: (envelope.result as Record<string, unknown> | null) ?? null,
198
161
  }
199
-
200
- return this._toReport(response.data as ReportResponse)
201
162
  }
202
163
 
203
- /**
204
- * List all reports for a graph (includes received shared reports).
205
- */
206
- async list(graphId: string): Promise<Report[]> {
207
- const response = await listReports({
208
- path: { graph_id: graphId },
209
- })
210
-
211
- if (response.error) {
212
- throw new Error(`List reports failed: ${JSON.stringify(response.error)}`)
213
- }
214
-
215
- const data = response.data as ReportListResponse
216
- return (data.reports ?? []).map((r) => this._toReport(r))
164
+ /** List all reports for a graph (includes received shared reports). */
165
+ async list(graphId: string): Promise<ReportListItem[]> {
166
+ const list = await this.gqlQuery(
167
+ graphId,
168
+ ListLedgerReportsDocument,
169
+ undefined,
170
+ 'List reports',
171
+ (data) => data.reports
172
+ )
173
+ return list?.reports ?? []
217
174
  }
218
175
 
219
- /**
220
- * Get a report with its available structures.
221
- */
222
- async get(graphId: string, reportId: string): Promise<Report> {
223
- const response = await getReport({
224
- path: { graph_id: graphId, report_id: reportId },
225
- })
226
-
227
- if (response.error) {
228
- throw new Error(`Get report failed: ${JSON.stringify(response.error)}`)
229
- }
230
-
231
- return this._toReport(response.data as ReportResponse)
176
+ /** Get a single report with its period list + available structures. */
177
+ async get(graphId: string, reportId: string): Promise<Report | null> {
178
+ return this.gqlQuery(
179
+ graphId,
180
+ GetLedgerReportDocument,
181
+ { reportId },
182
+ 'Get report',
183
+ (data) => data.report
184
+ )
232
185
  }
233
186
 
234
187
  /**
@@ -240,103 +193,78 @@ export class ReportClient {
240
193
  graphId: string,
241
194
  reportId: string,
242
195
  structureType: string
243
- ): Promise<StatementData> {
244
- const response = await getStatement({
245
- path: { graph_id: graphId, report_id: reportId, structure_type: structureType },
246
- })
247
-
248
- if (response.error) {
249
- throw new Error(`Get statement failed: ${JSON.stringify(response.error)}`)
250
- }
251
-
252
- const data = response.data as StatementResponse
253
- return {
254
- reportId: data.report_id,
255
- structureId: data.structure_id,
256
- structureName: data.structure_name,
257
- structureType: data.structure_type,
258
- periods: (data.periods ?? []).map((p) => ({
259
- start: p.start,
260
- end: p.end,
261
- label: p.label,
262
- })),
263
- rows: (data.rows ?? []).map((r: FactRowResponse) => ({
264
- elementId: r.element_id,
265
- elementQname: r.element_qname,
266
- elementName: r.element_name,
267
- classification: r.classification,
268
- values: r.values ?? [],
269
- isSubtotal: r.is_subtotal ?? false,
270
- depth: r.depth ?? 0,
271
- })),
272
- validation: data.validation
273
- ? {
274
- passed: (data.validation as ValidationCheckResponse).passed,
275
- checks: (data.validation as ValidationCheckResponse).checks,
276
- failures: (data.validation as ValidationCheckResponse).failures,
277
- warnings: (data.validation as ValidationCheckResponse).warnings,
278
- }
279
- : null,
280
- unmappedCount: data.unmapped_count ?? 0,
281
- }
196
+ ): Promise<StatementData | null> {
197
+ return this.gqlQuery(
198
+ graphId,
199
+ GetLedgerStatementDocument,
200
+ { reportId, structureType },
201
+ 'Get statement',
202
+ (data) => data.statement
203
+ )
282
204
  }
283
205
 
284
206
  /**
285
- * Regenerate a report with new period dates.
207
+ * Regenerate an existing report (async). Returns an operation id;
208
+ * subscribe via SSE for progress.
286
209
  */
287
210
  async regenerate(
288
211
  graphId: string,
289
212
  reportId: string,
290
- periodStart: string,
291
- periodEnd: string
292
- ): Promise<Report> {
293
- const response = await regenerateReport({
294
- path: { graph_id: graphId, report_id: reportId },
295
- body: { period_start: periodStart, period_end: periodEnd } as RegenerateReportRequest,
296
- })
297
-
298
- if (response.error) {
299
- throw new Error(`Regenerate report failed: ${JSON.stringify(response.error)}`)
213
+ periodStart?: string,
214
+ periodEnd?: string
215
+ ): Promise<ReportOperationAck> {
216
+ const envelope = await this.callOperation(
217
+ 'Regenerate report',
218
+ opRegenerateReport({
219
+ path: { graph_id: graphId },
220
+ body: {
221
+ report_id: reportId,
222
+ period_start: periodStart,
223
+ period_end: periodEnd,
224
+ } as Parameters<typeof opRegenerateReport>[0]['body'],
225
+ })
226
+ )
227
+ return {
228
+ operationId: envelope.operationId,
229
+ status: envelope.status,
230
+ result: (envelope.result as Record<string, unknown> | null) ?? null,
300
231
  }
301
-
302
- return this._toReport(response.data as ReportResponse)
303
232
  }
304
233
 
305
- /**
306
- * Delete a report and its generated facts.
307
- */
234
+ /** Delete a report and its generated facts. */
308
235
  async delete(graphId: string, reportId: string): Promise<void> {
309
- const response = await deleteReport({
310
- path: { graph_id: graphId, report_id: reportId },
311
- })
312
-
313
- if (response.error) {
314
- throw new Error(`Delete report failed: ${JSON.stringify(response.error)}`)
315
- }
236
+ await this.callOperation(
237
+ 'Delete report',
238
+ opDeleteReport({
239
+ path: { graph_id: graphId },
240
+ body: { report_id: reportId },
241
+ })
242
+ )
316
243
  }
317
244
 
318
245
  /**
319
- * Share a published report to all members of a publish list (snapshot copy).
246
+ * Share a published report to every member of a publish list (async).
247
+ * Each target graph receives a snapshot copy of the report's facts.
320
248
  */
321
- async share(graphId: string, reportId: string, publishListId: string): Promise<ShareResult> {
322
- const response = await shareReport({
323
- path: { graph_id: graphId, report_id: reportId },
324
- body: { publish_list_id: publishListId },
325
- })
326
-
327
- if (response.error) {
328
- throw new Error(`Share report failed: ${JSON.stringify(response.error)}`)
329
- }
330
-
331
- const data = response.data as ShareReportResponse
249
+ async share(
250
+ graphId: string,
251
+ reportId: string,
252
+ publishListId: string
253
+ ): Promise<ReportOperationAck> {
254
+ const envelope = await this.callOperation(
255
+ 'Share report',
256
+ opShareReport({
257
+ path: { graph_id: graphId },
258
+ body: {
259
+ report_id: reportId,
260
+ publish_list_id: publishListId,
261
+ } as Parameters<typeof opShareReport>[0]['body'],
262
+ })
263
+ )
332
264
  return {
333
- reportId: data.report_id,
334
- results: (data.results ?? []).map((r) => ({
335
- targetGraphId: r.target_graph_id,
336
- status: r.status as 'shared' | 'error',
337
- error: r.error ?? null,
338
- factCount: r.fact_count ?? 0,
339
- })),
265
+ operationId: envelope.operationId,
266
+ status: envelope.status,
267
+ result: (envelope.result as Record<string, unknown> | null) ?? null,
340
268
  }
341
269
  }
342
270
 
@@ -347,140 +275,152 @@ export class ReportClient {
347
275
 
348
276
  // ── Publish Lists ────────────────────────────────────────────────────
349
277
 
350
- async listPublishLists(graphId: string): Promise<PublishList[]> {
351
- const response = await listPublishLists({
352
- path: { graph_id: graphId },
353
- })
354
- if (response.error) {
355
- throw new Error(`List publish lists failed: ${JSON.stringify(response.error)}`)
356
- }
357
- const data = response.data as PublishListListResponse
358
- return (data.publish_lists ?? []).map((pl) => this._toPublishList(pl))
278
+ /** List publish lists with pagination. */
279
+ async listPublishLists(
280
+ graphId: string,
281
+ options?: { limit?: number; offset?: number }
282
+ ): Promise<PublishList[]> {
283
+ const list = await this.gqlQuery(
284
+ graphId,
285
+ ListLedgerPublishListsDocument,
286
+ {
287
+ limit: options?.limit ?? 100,
288
+ offset: options?.offset ?? 0,
289
+ },
290
+ 'List publish lists',
291
+ (data) => data.publishLists
292
+ )
293
+ return list?.publishLists ?? []
359
294
  }
360
295
 
296
+ /** Create a new publish list. */
361
297
  async createPublishList(
362
298
  graphId: string,
363
299
  name: string,
364
300
  description?: string
365
- ): Promise<PublishList> {
366
- const response = await createPublishList({
367
- path: { graph_id: graphId },
368
- body: { name, description: description ?? null },
369
- })
370
- if (response.error) {
371
- throw new Error(`Create publish list failed: ${JSON.stringify(response.error)}`)
301
+ ): Promise<Record<string, unknown>> {
302
+ const body: CreatePublishListRequest = {
303
+ name,
304
+ description: description ?? null,
372
305
  }
373
- return this._toPublishList(response.data as PublishListResponse)
306
+ const envelope = await this.callOperation(
307
+ 'Create publish list',
308
+ opCreatePublishList({ path: { graph_id: graphId }, body })
309
+ )
310
+ return (envelope.result ?? {}) as Record<string, unknown>
374
311
  }
375
312
 
376
- async getPublishList(graphId: string, listId: string): Promise<PublishListDetail> {
377
- const response = await getPublishList({
378
- path: { graph_id: graphId, list_id: listId },
379
- })
380
- if (response.error) {
381
- throw new Error(`Get publish list failed: ${JSON.stringify(response.error)}`)
382
- }
383
- const data = response.data as PublishListDetailResponse
384
- return {
385
- ...this._toPublishList(data),
386
- members: (data.members ?? []).map((m) => this._toMember(m)),
387
- }
313
+ /** Get a single publish list with its full member list. */
314
+ async getPublishList(graphId: string, listId: string): Promise<PublishListDetail | null> {
315
+ return this.gqlQuery(
316
+ graphId,
317
+ GetLedgerPublishListDocument,
318
+ { listId },
319
+ 'Get publish list',
320
+ (data) => data.publishList
321
+ )
388
322
  }
389
323
 
324
+ /** Update a publish list's name or description. */
390
325
  async updatePublishList(
391
326
  graphId: string,
392
327
  listId: string,
393
- updates: { name?: string; description?: string }
394
- ): Promise<PublishList> {
395
- const response = await updatePublishList({
396
- path: { graph_id: graphId, list_id: listId },
397
- body: updates,
398
- })
399
- if (response.error) {
400
- throw new Error(`Update publish list failed: ${JSON.stringify(response.error)}`)
401
- }
402
- return this._toPublishList(response.data as PublishListResponse)
328
+ updates: { name?: string; description?: string | null }
329
+ ): Promise<Record<string, unknown>> {
330
+ const envelope = await this.callOperation(
331
+ 'Update publish list',
332
+ opUpdatePublishList({
333
+ path: { graph_id: graphId },
334
+ body: {
335
+ list_id: listId,
336
+ name: updates.name,
337
+ description: updates.description ?? null,
338
+ } as UpdatePublishListOperation,
339
+ })
340
+ )
341
+ return (envelope.result ?? {}) as Record<string, unknown>
403
342
  }
404
343
 
344
+ /** Delete a publish list. */
405
345
  async deletePublishList(graphId: string, listId: string): Promise<void> {
406
- const response = await deletePublishList({
407
- path: { graph_id: graphId, list_id: listId },
408
- })
409
- if (response.error) {
410
- throw new Error(`Delete publish list failed: ${JSON.stringify(response.error)}`)
411
- }
346
+ await this.callOperation(
347
+ 'Delete publish list',
348
+ opDeletePublishList({
349
+ path: { graph_id: graphId },
350
+ body: { list_id: listId },
351
+ })
352
+ )
412
353
  }
413
354
 
355
+ /** Add target graphs as members of a publish list. */
414
356
  async addMembers(
415
357
  graphId: string,
416
358
  listId: string,
417
359
  targetGraphIds: string[]
418
- ): Promise<PublishListMember[]> {
419
- const response = await addPublishListMembers({
420
- path: { graph_id: graphId, list_id: listId },
421
- body: { target_graph_ids: targetGraphIds },
422
- })
423
- if (response.error) {
424
- throw new Error(`Add members failed: ${JSON.stringify(response.error)}`)
425
- }
426
- return ((response.data as PublishListMemberResponse[]) ?? []).map((m) => this._toMember(m))
360
+ ): Promise<Record<string, unknown>> {
361
+ const envelope = await this.callOperation(
362
+ 'Add publish list members',
363
+ opAddPublishListMembers({
364
+ path: { graph_id: graphId },
365
+ body: {
366
+ list_id: listId,
367
+ target_graph_ids: targetGraphIds,
368
+ } as AddPublishListMembersOperation,
369
+ })
370
+ )
371
+ return (envelope.result ?? {}) as Record<string, unknown>
427
372
  }
428
373
 
429
- async removeMember(graphId: string, listId: string, memberId: string): Promise<void> {
430
- const response = await removePublishListMember({
431
- path: { graph_id: graphId, list_id: listId, member_id: memberId },
432
- })
433
- if (response.error) {
434
- throw new Error(`Remove member failed: ${JSON.stringify(response.error)}`)
435
- }
374
+ /** Remove a single member from a publish list. */
375
+ async removeMember(
376
+ graphId: string,
377
+ listId: string,
378
+ memberId: string
379
+ ): Promise<{ deleted: boolean }> {
380
+ const envelope = await this.callOperation(
381
+ 'Remove publish list member',
382
+ opRemovePublishListMember({
383
+ path: { graph_id: graphId },
384
+ body: { list_id: listId, member_id: memberId },
385
+ })
386
+ )
387
+ return (envelope.result ?? { deleted: true }) as { deleted: boolean }
436
388
  }
437
389
 
438
- private _toPublishList(pl: PublishListResponse): PublishList {
439
- return {
440
- id: pl.id,
441
- name: pl.name,
442
- description: pl.description ?? null,
443
- memberCount: pl.member_count ?? 0,
444
- createdBy: pl.created_by,
445
- createdAt: pl.created_at,
446
- updatedAt: pl.updated_at,
447
- }
448
- }
390
+ // ── Internal helpers ────────────────────────────────────────────────
449
391
 
450
- private _toMember(m: PublishListMemberResponse): PublishListMember {
451
- return {
452
- id: m.id,
453
- targetGraphId: m.target_graph_id,
454
- targetGraphName: m.target_graph_name ?? null,
455
- targetOrgName: m.target_org_name ?? null,
456
- addedBy: m.added_by,
457
- addedAt: m.added_at,
392
+ private async gqlQuery<TData, TVars extends object, TResult>(
393
+ graphId: string,
394
+ document: TypedDocumentNode<TData, TVars>,
395
+ variables: TVars | undefined,
396
+ label: string,
397
+ pick: (data: TData) => TResult
398
+ ): Promise<TResult> {
399
+ try {
400
+ const client = this.gql.get(graphId)
401
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
402
+ const raw = client.request as (doc: unknown, vars?: unknown) => Promise<any>
403
+ const data = (await raw.call(client, document, variables)) as TData
404
+ return pick(data)
405
+ } catch (err) {
406
+ if (err instanceof ClientError) {
407
+ throw new Error(`${label} failed: ${JSON.stringify(err.response.errors ?? err.message)}`)
408
+ }
409
+ throw err
458
410
  }
459
411
  }
460
412
 
461
- private _toReport(r: ReportResponse): Report {
462
- return {
463
- id: r.id,
464
- name: r.name,
465
- taxonomyId: r.taxonomy_id,
466
- generationStatus: r.generation_status,
467
- periodType: r.period_type,
468
- periodStart: r.period_start ?? null,
469
- periodEnd: r.period_end ?? null,
470
- comparative: r.comparative,
471
- mappingId: r.mapping_id ?? null,
472
- aiGenerated: r.ai_generated ?? false,
473
- createdAt: r.created_at,
474
- lastGenerated: r.last_generated ?? null,
475
- structures: (r.structures ?? []).map((s: StructureSummary) => ({
476
- id: s.id,
477
- name: s.name,
478
- structureType: s.structure_type,
479
- })),
480
- entityName: r.entity_name ?? null,
481
- sourceGraphId: r.source_graph_id ?? null,
482
- sourceReportId: r.source_report_id ?? null,
483
- sharedAt: r.shared_at ?? null,
413
+ private async callOperation(
414
+ label: string,
415
+ call: Promise<{ data?: OperationEnvelope; error?: unknown }>
416
+ ): Promise<OperationEnvelope> {
417
+ const response = await call
418
+ if (response.error !== undefined) {
419
+ throw new Error(`${label} failed: ${JSON.stringify(response.error)}`)
420
+ }
421
+ if (response.data === undefined) {
422
+ throw new Error(`${label} failed: empty response`)
484
423
  }
424
+ return response.data
485
425
  }
486
426
  }