@robosystems/client 0.2.49 → 0.3.1

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 (191) hide show
  1. package/extensions/InvestorClient.d.ts +98 -0
  2. package/extensions/InvestorClient.js +223 -0
  3. package/extensions/InvestorClient.ts +508 -0
  4. package/extensions/LedgerClient.d.ts +190 -309
  5. package/extensions/LedgerClient.js +268 -587
  6. package/extensions/LedgerClient.ts +784 -903
  7. package/extensions/ReportClient.d.ts +82 -113
  8. package/extensions/ReportClient.js +124 -211
  9. package/extensions/ReportClient.ts +305 -358
  10. package/extensions/config.d.ts +19 -0
  11. package/extensions/config.js +1 -1
  12. package/extensions/config.ts +22 -2
  13. package/extensions/graphql/client.d.ts +82 -0
  14. package/extensions/graphql/client.js +149 -0
  15. package/extensions/graphql/client.ts +189 -0
  16. package/extensions/graphql/generated/graphql.d.ts +1786 -0
  17. package/extensions/graphql/generated/graphql.js +2671 -0
  18. package/extensions/graphql/generated/graphql.ts +4491 -0
  19. package/extensions/graphql/queries/investor/holdings.d.ts +8 -0
  20. package/extensions/graphql/queries/investor/holdings.js +36 -0
  21. package/extensions/graphql/queries/investor/holdings.ts +34 -0
  22. package/extensions/graphql/queries/investor/portfolio.d.ts +4 -0
  23. package/extensions/graphql/queries/investor/portfolio.js +21 -0
  24. package/extensions/graphql/queries/investor/portfolio.ts +19 -0
  25. package/extensions/graphql/queries/investor/portfolios.d.ts +4 -0
  26. package/extensions/graphql/queries/investor/portfolios.js +29 -0
  27. package/extensions/graphql/queries/investor/portfolios.ts +27 -0
  28. package/extensions/graphql/queries/investor/position.d.ts +4 -0
  29. package/extensions/graphql/queries/investor/position.js +33 -0
  30. package/extensions/graphql/queries/investor/position.ts +31 -0
  31. package/extensions/graphql/queries/investor/positions.d.ts +8 -0
  32. package/extensions/graphql/queries/investor/positions.js +57 -0
  33. package/extensions/graphql/queries/investor/positions.ts +55 -0
  34. package/extensions/graphql/queries/investor/securities.d.ts +8 -0
  35. package/extensions/graphql/queries/investor/securities.js +50 -0
  36. package/extensions/graphql/queries/investor/securities.ts +48 -0
  37. package/extensions/graphql/queries/investor/security.d.ts +4 -0
  38. package/extensions/graphql/queries/investor/security.js +26 -0
  39. package/extensions/graphql/queries/investor/security.ts +24 -0
  40. package/extensions/graphql/queries/ledger/accountRollups.d.ts +7 -0
  41. package/extensions/graphql/queries/ledger/accountRollups.js +36 -0
  42. package/extensions/graphql/queries/ledger/accountRollups.ts +34 -0
  43. package/extensions/graphql/queries/ledger/accountTree.d.ts +11 -0
  44. package/extensions/graphql/queries/ledger/accountTree.js +61 -0
  45. package/extensions/graphql/queries/ledger/accountTree.ts +59 -0
  46. package/extensions/graphql/queries/ledger/accounts.d.ts +8 -0
  47. package/extensions/graphql/queries/ledger/accounts.js +45 -0
  48. package/extensions/graphql/queries/ledger/accounts.ts +43 -0
  49. package/extensions/graphql/queries/ledger/closingBookStructures.d.ts +6 -0
  50. package/extensions/graphql/queries/ledger/closingBookStructures.js +27 -0
  51. package/extensions/graphql/queries/ledger/closingBookStructures.ts +25 -0
  52. package/extensions/graphql/queries/ledger/elements.d.ts +6 -0
  53. package/extensions/graphql/queries/ledger/elements.js +56 -0
  54. package/extensions/graphql/queries/ledger/elements.ts +54 -0
  55. package/extensions/graphql/queries/ledger/entities.d.ts +7 -0
  56. package/extensions/graphql/queries/ledger/entities.js +31 -0
  57. package/extensions/graphql/queries/ledger/entities.ts +29 -0
  58. package/extensions/graphql/queries/ledger/entity.d.ts +14 -0
  59. package/extensions/graphql/queries/ledger/entity.js +55 -0
  60. package/extensions/graphql/queries/ledger/entity.ts +54 -0
  61. package/extensions/graphql/queries/ledger/fiscalCalendar.d.ts +8 -0
  62. package/extensions/graphql/queries/ledger/fiscalCalendar.js +35 -0
  63. package/extensions/graphql/queries/ledger/fiscalCalendar.ts +33 -0
  64. package/extensions/graphql/queries/ledger/mappedTrialBalance.d.ts +9 -0
  65. package/extensions/graphql/queries/ledger/mappedTrialBalance.js +29 -0
  66. package/extensions/graphql/queries/ledger/mappedTrialBalance.ts +27 -0
  67. package/extensions/graphql/queries/ledger/mapping.d.ts +5 -0
  68. package/extensions/graphql/queries/ledger/mapping.js +35 -0
  69. package/extensions/graphql/queries/ledger/mapping.ts +33 -0
  70. package/extensions/graphql/queries/ledger/mappingCoverage.d.ts +5 -0
  71. package/extensions/graphql/queries/ledger/mappingCoverage.js +22 -0
  72. package/extensions/graphql/queries/ledger/mappingCoverage.ts +20 -0
  73. package/extensions/graphql/queries/ledger/mappings.d.ts +6 -0
  74. package/extensions/graphql/queries/ledger/mappings.js +23 -0
  75. package/extensions/graphql/queries/ledger/mappings.ts +21 -0
  76. package/extensions/graphql/queries/ledger/periodCloseStatus.d.ts +6 -0
  77. package/extensions/graphql/queries/ledger/periodCloseStatus.js +29 -0
  78. package/extensions/graphql/queries/ledger/periodCloseStatus.ts +27 -0
  79. package/extensions/graphql/queries/ledger/periodDrafts.d.ts +8 -0
  80. package/extensions/graphql/queries/ledger/periodDrafts.js +45 -0
  81. package/extensions/graphql/queries/ledger/periodDrafts.ts +43 -0
  82. package/extensions/graphql/queries/ledger/publishList.d.ts +5 -0
  83. package/extensions/graphql/queries/ledger/publishList.js +29 -0
  84. package/extensions/graphql/queries/ledger/publishList.ts +27 -0
  85. package/extensions/graphql/queries/ledger/publishLists.d.ts +5 -0
  86. package/extensions/graphql/queries/ledger/publishLists.js +29 -0
  87. package/extensions/graphql/queries/ledger/publishLists.ts +27 -0
  88. package/extensions/graphql/queries/ledger/report.d.ts +5 -0
  89. package/extensions/graphql/queries/ledger/report.js +40 -0
  90. package/extensions/graphql/queries/ledger/report.ts +38 -0
  91. package/extensions/graphql/queries/ledger/reportingTaxonomy.d.ts +6 -0
  92. package/extensions/graphql/queries/ledger/reportingTaxonomy.js +27 -0
  93. package/extensions/graphql/queries/ledger/reportingTaxonomy.ts +25 -0
  94. package/extensions/graphql/queries/ledger/reports.d.ts +8 -0
  95. package/extensions/graphql/queries/ledger/reports.js +45 -0
  96. package/extensions/graphql/queries/ledger/reports.ts +43 -0
  97. package/extensions/graphql/queries/ledger/scheduleFacts.d.ts +7 -0
  98. package/extensions/graphql/queries/ledger/scheduleFacts.js +24 -0
  99. package/extensions/graphql/queries/ledger/scheduleFacts.ts +22 -0
  100. package/extensions/graphql/queries/ledger/schedules.d.ts +6 -0
  101. package/extensions/graphql/queries/ledger/schedules.js +24 -0
  102. package/extensions/graphql/queries/ledger/schedules.ts +22 -0
  103. package/extensions/graphql/queries/ledger/statement.d.ts +9 -0
  104. package/extensions/graphql/queries/ledger/statement.js +43 -0
  105. package/extensions/graphql/queries/ledger/statement.ts +41 -0
  106. package/extensions/graphql/queries/ledger/structures.d.ts +5 -0
  107. package/extensions/graphql/queries/ledger/structures.js +22 -0
  108. package/extensions/graphql/queries/ledger/structures.ts +20 -0
  109. package/extensions/graphql/queries/ledger/summary.d.ts +7 -0
  110. package/extensions/graphql/queries/ledger/summary.js +25 -0
  111. package/extensions/graphql/queries/ledger/summary.ts +23 -0
  112. package/extensions/graphql/queries/ledger/taxonomies.d.ts +5 -0
  113. package/extensions/graphql/queries/ledger/taxonomies.js +28 -0
  114. package/extensions/graphql/queries/ledger/taxonomies.ts +26 -0
  115. package/extensions/graphql/queries/ledger/transaction.d.ts +6 -0
  116. package/extensions/graphql/queries/ledger/transaction.js +49 -0
  117. package/extensions/graphql/queries/ledger/transaction.ts +47 -0
  118. package/extensions/graphql/queries/ledger/transactions.d.ts +7 -0
  119. package/extensions/graphql/queries/ledger/transactions.js +49 -0
  120. package/extensions/graphql/queries/ledger/transactions.ts +47 -0
  121. package/extensions/graphql/queries/ledger/trialBalance.d.ts +7 -0
  122. package/extensions/graphql/queries/ledger/trialBalance.js +28 -0
  123. package/extensions/graphql/queries/ledger/trialBalance.ts +26 -0
  124. package/extensions/graphql/queries/ledger/unmappedElements.d.ts +8 -0
  125. package/extensions/graphql/queries/ledger/unmappedElements.js +29 -0
  126. package/extensions/graphql/queries/ledger/unmappedElements.ts +27 -0
  127. package/extensions/hooks.d.ts +1 -1
  128. package/extensions/index.d.ts +18 -1
  129. package/extensions/index.js +26 -1
  130. package/extensions/index.ts +49 -2
  131. package/index.ts +2 -2
  132. package/package.json +14 -5
  133. package/sdk/index.d.ts +2 -2
  134. package/sdk/index.js +38 -73
  135. package/sdk/index.ts +2 -2
  136. package/sdk/sdk.gen.d.ts +100 -325
  137. package/sdk/sdk.gen.js +228 -592
  138. package/sdk/sdk.gen.ts +193 -556
  139. package/sdk/types.gen.d.ts +4522 -7708
  140. package/sdk/types.gen.ts +4569 -7983
  141. package/sdk.gen.d.ts +100 -325
  142. package/sdk.gen.js +228 -592
  143. package/sdk.gen.ts +193 -556
  144. package/types.gen.d.ts +4522 -7708
  145. package/types.gen.ts +4569 -7983
  146. package/extensions/AgentClient.test.ts +0 -403
  147. package/extensions/LedgerClient.test.ts +0 -1655
  148. package/extensions/OperationClient.test.ts +0 -365
  149. package/extensions/QueryClient.test.ts +0 -432
  150. package/extensions/ReportClient.test.ts +0 -828
  151. package/extensions/SSEClient.test.ts +0 -375
  152. package/extensions/config.test.ts +0 -199
  153. package/extensions/hooks.test.ts +0 -373
  154. package/extensions/index.test.ts +0 -420
  155. package/sdk-extensions/AgentClient.d.ts +0 -82
  156. package/sdk-extensions/AgentClient.js +0 -218
  157. package/sdk-extensions/AgentClient.test.ts +0 -403
  158. package/sdk-extensions/AgentClient.ts +0 -321
  159. package/sdk-extensions/LedgerClient.d.ts +0 -416
  160. package/sdk-extensions/LedgerClient.js +0 -737
  161. package/sdk-extensions/LedgerClient.test.ts +0 -1655
  162. package/sdk-extensions/LedgerClient.ts +0 -1249
  163. package/sdk-extensions/OperationClient.d.ts +0 -65
  164. package/sdk-extensions/OperationClient.js +0 -251
  165. package/sdk-extensions/OperationClient.test.ts +0 -365
  166. package/sdk-extensions/OperationClient.ts +0 -324
  167. package/sdk-extensions/QueryClient.d.ts +0 -52
  168. package/sdk-extensions/QueryClient.js +0 -313
  169. package/sdk-extensions/QueryClient.test.ts +0 -432
  170. package/sdk-extensions/QueryClient.ts +0 -420
  171. package/sdk-extensions/README.md +0 -901
  172. package/sdk-extensions/ReportClient.d.ts +0 -151
  173. package/sdk-extensions/ReportClient.js +0 -278
  174. package/sdk-extensions/ReportClient.test.ts +0 -828
  175. package/sdk-extensions/ReportClient.ts +0 -486
  176. package/sdk-extensions/SSEClient.d.ts +0 -62
  177. package/sdk-extensions/SSEClient.js +0 -154
  178. package/sdk-extensions/SSEClient.test.ts +0 -375
  179. package/sdk-extensions/SSEClient.ts +0 -210
  180. package/sdk-extensions/config.d.ts +0 -57
  181. package/sdk-extensions/config.js +0 -152
  182. package/sdk-extensions/config.test.ts +0 -199
  183. package/sdk-extensions/config.ts +0 -175
  184. package/sdk-extensions/hooks.d.ts +0 -110
  185. package/sdk-extensions/hooks.js +0 -384
  186. package/sdk-extensions/hooks.test.ts +0 -373
  187. package/sdk-extensions/hooks.ts +0 -459
  188. package/sdk-extensions/index.d.ts +0 -63
  189. package/sdk-extensions/index.js +0 -164
  190. package/sdk-extensions/index.test.ts +0 -420
  191. package/sdk-extensions/index.ts +0 -203
@@ -3,135 +3,75 @@
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 type { TokenProvider } from './graphql/client'
46
+ import { GraphQLClientCache } from './graphql/client'
47
+ import {
48
+ GetLedgerPublishListDocument,
49
+ GetLedgerReportDocument,
50
+ GetLedgerStatementDocument,
51
+ ListLedgerPublishListsDocument,
52
+ ListLedgerReportsDocument,
53
+ type GetLedgerPublishListQuery,
54
+ type GetLedgerReportQuery,
55
+ type GetLedgerStatementQuery,
56
+ type ListLedgerPublishListsQuery,
57
+ type ListLedgerReportsQuery,
58
+ } from './graphql/generated/graphql'
59
+
60
+ // ── Types derived from GraphQL codegen ──────────────────────────────────
61
+
62
+ export type Report = NonNullable<GetLedgerReportQuery['report']>
63
+ export type ReportListItem = NonNullable<ListLedgerReportsQuery['reports']>['reports'][number]
64
+ export type StatementData = NonNullable<GetLedgerStatementQuery['statement']>
65
+ export type StatementPeriod = StatementData['periods'][number]
66
+ export type StatementRow = StatementData['rows'][number]
67
+
68
+ export type PublishList = NonNullable<
69
+ ListLedgerPublishListsQuery['publishLists']
70
+ >['publishLists'][number]
71
+ export type PublishListDetail = NonNullable<GetLedgerPublishListQuery['publishList']>
72
+ export type PublishListMember = PublishListDetail['members'][number]
73
+
74
+ // ── Caller-facing option interfaces ─────────────────────────────────────
135
75
 
136
76
  export interface PeriodSpecInput {
137
77
  start: string
@@ -151,29 +91,60 @@ export interface CreateReportOptions {
151
91
  periods?: PeriodSpecInput[]
152
92
  }
153
93
 
94
+ /**
95
+ * Envelope around a report operation. `status === "completed"` means the
96
+ * backend produced the report synchronously — `result` contains the
97
+ * freshly-created report shape (same fields as `ReportListItem`), so
98
+ * consumers can read `result?.id` immediately. For pending/failed
99
+ * dispatches, `result` is null and consumers should subscribe to
100
+ * `/v1/operations/{operationId}/stream` for progress.
101
+ *
102
+ * The loose `{ id; name; ... }` shape here intentionally mirrors the
103
+ * GraphQL `report` field without pulling in every nullable child relation
104
+ * — `create_report` and `regenerate_report` return a freshly-generated
105
+ * row, not a fully-resolved GraphQL projection.
106
+ */
107
+ export interface ReportOperationAck {
108
+ operationId: string
109
+ status: OperationEnvelope['status']
110
+ /**
111
+ * Synchronous command result. Populated for `status === "completed"`
112
+ * dispatches where the backend produced the report inline.
113
+ */
114
+ result: Record<string, unknown> | null
115
+ }
116
+
154
117
  // ── Client ──────────────────────────────────────────────────────────────
155
118
 
119
+ interface ReportClientConfig {
120
+ baseUrl: string
121
+ credentials?: 'include' | 'same-origin' | 'omit'
122
+ headers?: Record<string, string>
123
+ /** Static credential — use `tokenProvider` instead if the JWT rotates. */
124
+ token?: string
125
+ /**
126
+ * Dynamic credential callback. When set, invoked on every GraphQL
127
+ * request so refreshes flow through automatically.
128
+ */
129
+ tokenProvider?: TokenProvider
130
+ }
131
+
156
132
  export class ReportClient {
157
- private config: {
158
- baseUrl: string
159
- credentials?: 'include' | 'same-origin' | 'omit'
160
- headers?: Record<string, string>
161
- token?: string
162
- }
133
+ private config: ReportClientConfig
134
+ private gql: GraphQLClientCache
163
135
 
164
- constructor(config: {
165
- baseUrl: string
166
- credentials?: 'include' | 'same-origin' | 'omit'
167
- headers?: Record<string, string>
168
- token?: string
169
- }) {
136
+ constructor(config: ReportClientConfig) {
170
137
  this.config = config
138
+ this.gql = new GraphQLClientCache(config)
171
139
  }
172
140
 
141
+ // ── Reports ─────────────────────────────────────────────────────────
142
+
173
143
  /**
174
- * Create a report generates facts for all structures in the taxonomy.
144
+ * Kick off report creation (async). Use the returned `operationId` to
145
+ * subscribe to progress via SSE, then call `get()` once finished.
175
146
  */
176
- async create(graphId: string, options: CreateReportOptions): Promise<Report> {
147
+ async create(graphId: string, options: CreateReportOptions): Promise<ReportOperationAck> {
177
148
  const body: CreateReportRequest = {
178
149
  name: options.name,
179
150
  mapping_id: options.mappingId,
@@ -183,52 +154,41 @@ export class ReportClient {
183
154
  period_type: options.periodType ?? 'quarterly',
184
155
  comparative: options.comparative ?? true,
185
156
  }
186
-
187
157
  if (options.periods && options.periods.length > 0) {
188
158
  body.periods = options.periods
189
159
  }
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)}`)
160
+ const envelope = await this.callOperation(
161
+ 'Create report',
162
+ opCreateReport({ path: { graph_id: graphId }, body })
163
+ )
164
+ return {
165
+ operationId: envelope.operationId,
166
+ status: envelope.status,
167
+ result: (envelope.result as Record<string, unknown> | null) ?? null,
198
168
  }
199
-
200
- return this._toReport(response.data as ReportResponse)
201
169
  }
202
170
 
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))
171
+ /** List all reports for a graph (includes received shared reports). */
172
+ async list(graphId: string): Promise<ReportListItem[]> {
173
+ const list = await this.gqlQuery(
174
+ graphId,
175
+ ListLedgerReportsDocument,
176
+ undefined,
177
+ 'List reports',
178
+ (data) => data.reports
179
+ )
180
+ return list?.reports ?? []
217
181
  }
218
182
 
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)
183
+ /** Get a single report with its period list + available structures. */
184
+ async get(graphId: string, reportId: string): Promise<Report | null> {
185
+ return this.gqlQuery(
186
+ graphId,
187
+ GetLedgerReportDocument,
188
+ { reportId },
189
+ 'Get report',
190
+ (data) => data.report
191
+ )
232
192
  }
233
193
 
234
194
  /**
@@ -240,103 +200,78 @@ export class ReportClient {
240
200
  graphId: string,
241
201
  reportId: string,
242
202
  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
- }
203
+ ): Promise<StatementData | null> {
204
+ return this.gqlQuery(
205
+ graphId,
206
+ GetLedgerStatementDocument,
207
+ { reportId, structureType },
208
+ 'Get statement',
209
+ (data) => data.statement
210
+ )
282
211
  }
283
212
 
284
213
  /**
285
- * Regenerate a report with new period dates.
214
+ * Regenerate an existing report (async). Returns an operation id;
215
+ * subscribe via SSE for progress.
286
216
  */
287
217
  async regenerate(
288
218
  graphId: string,
289
219
  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)}`)
220
+ periodStart?: string,
221
+ periodEnd?: string
222
+ ): Promise<ReportOperationAck> {
223
+ const envelope = await this.callOperation(
224
+ 'Regenerate report',
225
+ opRegenerateReport({
226
+ path: { graph_id: graphId },
227
+ body: {
228
+ report_id: reportId,
229
+ period_start: periodStart,
230
+ period_end: periodEnd,
231
+ } as Parameters<typeof opRegenerateReport>[0]['body'],
232
+ })
233
+ )
234
+ return {
235
+ operationId: envelope.operationId,
236
+ status: envelope.status,
237
+ result: (envelope.result as Record<string, unknown> | null) ?? null,
300
238
  }
301
-
302
- return this._toReport(response.data as ReportResponse)
303
239
  }
304
240
 
305
- /**
306
- * Delete a report and its generated facts.
307
- */
241
+ /** Delete a report and its generated facts. */
308
242
  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
- }
243
+ await this.callOperation(
244
+ 'Delete report',
245
+ opDeleteReport({
246
+ path: { graph_id: graphId },
247
+ body: { report_id: reportId },
248
+ })
249
+ )
316
250
  }
317
251
 
318
252
  /**
319
- * Share a published report to all members of a publish list (snapshot copy).
253
+ * Share a published report to every member of a publish list (async).
254
+ * Each target graph receives a snapshot copy of the report's facts.
320
255
  */
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
256
+ async share(
257
+ graphId: string,
258
+ reportId: string,
259
+ publishListId: string
260
+ ): Promise<ReportOperationAck> {
261
+ const envelope = await this.callOperation(
262
+ 'Share report',
263
+ opShareReport({
264
+ path: { graph_id: graphId },
265
+ body: {
266
+ report_id: reportId,
267
+ publish_list_id: publishListId,
268
+ } as Parameters<typeof opShareReport>[0]['body'],
269
+ })
270
+ )
332
271
  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
- })),
272
+ operationId: envelope.operationId,
273
+ status: envelope.status,
274
+ result: (envelope.result as Record<string, unknown> | null) ?? null,
340
275
  }
341
276
  }
342
277
 
@@ -347,140 +282,152 @@ export class ReportClient {
347
282
 
348
283
  // ── Publish Lists ────────────────────────────────────────────────────
349
284
 
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))
285
+ /** List publish lists with pagination. */
286
+ async listPublishLists(
287
+ graphId: string,
288
+ options?: { limit?: number; offset?: number }
289
+ ): Promise<PublishList[]> {
290
+ const list = await this.gqlQuery(
291
+ graphId,
292
+ ListLedgerPublishListsDocument,
293
+ {
294
+ limit: options?.limit ?? 100,
295
+ offset: options?.offset ?? 0,
296
+ },
297
+ 'List publish lists',
298
+ (data) => data.publishLists
299
+ )
300
+ return list?.publishLists ?? []
359
301
  }
360
302
 
303
+ /** Create a new publish list. */
361
304
  async createPublishList(
362
305
  graphId: string,
363
306
  name: string,
364
307
  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)}`)
308
+ ): Promise<Record<string, unknown>> {
309
+ const body: CreatePublishListRequest = {
310
+ name,
311
+ description: description ?? null,
372
312
  }
373
- return this._toPublishList(response.data as PublishListResponse)
313
+ const envelope = await this.callOperation(
314
+ 'Create publish list',
315
+ opCreatePublishList({ path: { graph_id: graphId }, body })
316
+ )
317
+ return (envelope.result ?? {}) as Record<string, unknown>
374
318
  }
375
319
 
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
- }
320
+ /** Get a single publish list with its full member list. */
321
+ async getPublishList(graphId: string, listId: string): Promise<PublishListDetail | null> {
322
+ return this.gqlQuery(
323
+ graphId,
324
+ GetLedgerPublishListDocument,
325
+ { listId },
326
+ 'Get publish list',
327
+ (data) => data.publishList
328
+ )
388
329
  }
389
330
 
331
+ /** Update a publish list's name or description. */
390
332
  async updatePublishList(
391
333
  graphId: string,
392
334
  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)
335
+ updates: { name?: string; description?: string | null }
336
+ ): Promise<Record<string, unknown>> {
337
+ const envelope = await this.callOperation(
338
+ 'Update publish list',
339
+ opUpdatePublishList({
340
+ path: { graph_id: graphId },
341
+ body: {
342
+ list_id: listId,
343
+ name: updates.name,
344
+ description: updates.description ?? null,
345
+ } as UpdatePublishListOperation,
346
+ })
347
+ )
348
+ return (envelope.result ?? {}) as Record<string, unknown>
403
349
  }
404
350
 
351
+ /** Delete a publish list. */
405
352
  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
- }
353
+ await this.callOperation(
354
+ 'Delete publish list',
355
+ opDeletePublishList({
356
+ path: { graph_id: graphId },
357
+ body: { list_id: listId },
358
+ })
359
+ )
412
360
  }
413
361
 
362
+ /** Add target graphs as members of a publish list. */
414
363
  async addMembers(
415
364
  graphId: string,
416
365
  listId: string,
417
366
  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))
367
+ ): Promise<Record<string, unknown>> {
368
+ const envelope = await this.callOperation(
369
+ 'Add publish list members',
370
+ opAddPublishListMembers({
371
+ path: { graph_id: graphId },
372
+ body: {
373
+ list_id: listId,
374
+ target_graph_ids: targetGraphIds,
375
+ } as AddPublishListMembersOperation,
376
+ })
377
+ )
378
+ return (envelope.result ?? {}) as Record<string, unknown>
427
379
  }
428
380
 
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
- }
381
+ /** Remove a single member from a publish list. */
382
+ async removeMember(
383
+ graphId: string,
384
+ listId: string,
385
+ memberId: string
386
+ ): Promise<{ deleted: boolean }> {
387
+ const envelope = await this.callOperation(
388
+ 'Remove publish list member',
389
+ opRemovePublishListMember({
390
+ path: { graph_id: graphId },
391
+ body: { list_id: listId, member_id: memberId },
392
+ })
393
+ )
394
+ return (envelope.result ?? { deleted: true }) as { deleted: boolean }
436
395
  }
437
396
 
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
- }
397
+ // ── Internal helpers ────────────────────────────────────────────────
449
398
 
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,
399
+ private async gqlQuery<TData, TVars extends object, TResult>(
400
+ graphId: string,
401
+ document: TypedDocumentNode<TData, TVars>,
402
+ variables: TVars | undefined,
403
+ label: string,
404
+ pick: (data: TData) => TResult
405
+ ): Promise<TResult> {
406
+ try {
407
+ const client = this.gql.get(graphId)
408
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
409
+ const raw = client.request as (doc: unknown, vars?: unknown) => Promise<any>
410
+ const data = (await raw.call(client, document, variables)) as TData
411
+ return pick(data)
412
+ } catch (err) {
413
+ if (err instanceof ClientError) {
414
+ throw new Error(`${label} failed: ${JSON.stringify(err.response.errors ?? err.message)}`)
415
+ }
416
+ throw err
458
417
  }
459
418
  }
460
419
 
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,
420
+ private async callOperation(
421
+ label: string,
422
+ call: Promise<{ data?: OperationEnvelope; error?: unknown }>
423
+ ): Promise<OperationEnvelope> {
424
+ const response = await call
425
+ if (response.error !== undefined) {
426
+ throw new Error(`${label} failed: ${JSON.stringify(response.error)}`)
427
+ }
428
+ if (response.data === undefined) {
429
+ throw new Error(`${label} failed: empty response`)
484
430
  }
431
+ return response.data
485
432
  }
486
433
  }