@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
@@ -2,324 +2,192 @@
2
2
  "use strict";
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.LedgerClient = void 0;
5
- /**
6
- * Ledger Client for RoboSystems API
7
- *
8
- * High-level client for all ledger concerns: chart of accounts, transactions,
9
- * trial balance, taxonomy, mappings, and AI auto-mapping. This is the
10
- * operational backbone — reports consume these as inputs.
11
- */
5
+ const graphql_request_1 = require("graphql-request");
12
6
  const sdk_gen_1 = require("../sdk.gen");
13
- // ── Client ──────────────────────────────────────────────────────────────
7
+ const client_1 = require("./graphql/client");
8
+ const graphql_1 = require("./graphql/generated/graphql");
14
9
  class LedgerClient {
15
10
  constructor(config) {
16
11
  this.config = config;
12
+ this.gql = new client_1.GraphQLClientCache(config);
17
13
  }
18
14
  // ── Entity ──────────────────────────────────────────────────────────
19
15
  /**
20
16
  * Get the entity (company/organization) for this graph.
17
+ * Returns null when the ledger has no entity yet.
21
18
  */
22
19
  async getEntity(graphId) {
23
- const response = await (0, sdk_gen_1.getLedgerEntity)({
24
- path: { graph_id: graphId },
25
- });
26
- if (response.response.status === 404)
27
- return null;
28
- if (response.error) {
29
- throw new Error(`Get entity failed: ${JSON.stringify(response.error)}`);
30
- }
31
- const data = response.data;
32
- return {
33
- id: data.id,
34
- name: data.name,
35
- legalName: data.legal_name ?? null,
36
- entityType: data.entity_type ?? null,
37
- industry: data.industry ?? null,
38
- status: data.status ?? null,
39
- };
20
+ return this.gqlQuery(graphId, graphql_1.GetLedgerEntityDocument, undefined, 'Get entity', (data) => data.entity);
21
+ }
22
+ /** List all entities for this graph, optionally filtered by source system. */
23
+ async listEntities(graphId, options) {
24
+ return this.gqlQuery(graphId, graphql_1.ListLedgerEntitiesDocument, { source: options?.source ?? null }, 'List entities', (data) => data.entities);
40
25
  }
41
- // ── Accounts (Chart of Accounts) ───────────────────────────────────
42
26
  /**
43
- * List accounts (flat).
27
+ * Update the entity for this graph. Only non-null fields are applied.
28
+ * Returns the updated entity.
44
29
  */
45
- async listAccounts(graphId) {
46
- const response = await (0, sdk_gen_1.listLedgerAccounts)({
30
+ async updateEntity(graphId, updates) {
31
+ const envelope = await this.callOperation('Update entity', (0, sdk_gen_1.opUpdateEntity)({
47
32
  path: { graph_id: graphId },
48
- });
49
- if (response.error) {
50
- throw new Error(`List accounts failed: ${JSON.stringify(response.error)}`);
51
- }
52
- return response.data;
33
+ body: updates,
34
+ }));
35
+ return envelope.result;
53
36
  }
54
- /**
55
- * Get the account tree (hierarchical).
56
- */
37
+ // ── Summary ────────────────────────────────────────────────────────
38
+ /** Ledger rollup counts + QB sync metadata. */
39
+ async getSummary(graphId) {
40
+ return this.gqlQuery(graphId, graphql_1.GetLedgerSummaryDocument, undefined, 'Get summary', (data) => data.summary);
41
+ }
42
+ // ── Accounts (Chart of Accounts) ───────────────────────────────────
43
+ /** List CoA accounts with optional filters and pagination. */
44
+ async listAccounts(graphId, options) {
45
+ return this.gqlQuery(graphId, graphql_1.ListLedgerAccountsDocument, {
46
+ classification: options?.classification ?? null,
47
+ isActive: options?.isActive ?? null,
48
+ limit: options?.limit ?? 100,
49
+ offset: options?.offset ?? 0,
50
+ }, 'List accounts', (data) => data.accounts);
51
+ }
52
+ /** Hierarchical Chart of Accounts (up to 4 levels deep). */
57
53
  async getAccountTree(graphId) {
58
- const response = await (0, sdk_gen_1.getLedgerAccountTree)({
59
- path: { graph_id: graphId },
60
- });
61
- if (response.error) {
62
- throw new Error(`Get account tree failed: ${JSON.stringify(response.error)}`);
63
- }
64
- return response.data;
54
+ return this.gqlQuery(graphId, graphql_1.GetLedgerAccountTreeDocument, undefined, 'Get account tree', (data) => data.accountTree);
55
+ }
56
+ /** Accounts rolled up to reporting concepts via a mapping structure. */
57
+ async getAccountRollups(graphId, options) {
58
+ return this.gqlQuery(graphId, graphql_1.GetLedgerAccountRollupsDocument, {
59
+ mappingId: options?.mappingId ?? null,
60
+ startDate: options?.startDate ?? null,
61
+ endDate: options?.endDate ?? null,
62
+ }, 'Get account rollups', (data) => data.accountRollups);
65
63
  }
66
64
  // ── Transactions ────────────────────────────────────────────────────
67
- /**
68
- * List transactions with optional date filters.
69
- */
65
+ /** List transactions with optional type + date filters and pagination. */
70
66
  async listTransactions(graphId, options) {
71
- const response = await (0, sdk_gen_1.listLedgerTransactions)({
72
- path: { graph_id: graphId },
73
- query: {
74
- start_date: options?.startDate,
75
- end_date: options?.endDate,
76
- limit: options?.limit,
77
- offset: options?.offset,
78
- },
79
- });
80
- if (response.error) {
81
- throw new Error(`List transactions failed: ${JSON.stringify(response.error)}`);
82
- }
83
- return response.data;
67
+ return this.gqlQuery(graphId, graphql_1.ListLedgerTransactionsDocument, {
68
+ type: options?.type ?? null,
69
+ startDate: options?.startDate ?? null,
70
+ endDate: options?.endDate ?? null,
71
+ limit: options?.limit ?? 100,
72
+ offset: options?.offset ?? 0,
73
+ }, 'List transactions', (data) => data.transactions);
84
74
  }
85
- /**
86
- * Get transaction detail with entries and line items.
87
- */
75
+ /** Get transaction detail with entries + line items. */
88
76
  async getTransaction(graphId, transactionId) {
89
- const response = await (0, sdk_gen_1.getLedgerTransaction)({
90
- path: { graph_id: graphId, transaction_id: transactionId },
91
- });
92
- if (response.error) {
93
- throw new Error(`Get transaction failed: ${JSON.stringify(response.error)}`);
94
- }
95
- return response.data;
77
+ return this.gqlQuery(graphId, graphql_1.GetLedgerTransactionDocument, { transactionId }, 'Get transaction', (data) => data.transaction);
96
78
  }
97
79
  // ── Trial Balance ──────────────────────────────────────────────────
98
- /**
99
- * Get trial balance (CoA-level debits/credits).
100
- */
80
+ /** Trial balance by raw CoA account. */
101
81
  async getTrialBalance(graphId, options) {
102
- const response = await (0, sdk_gen_1.getLedgerTrialBalance)({
103
- path: { graph_id: graphId },
104
- query: {
105
- start_date: options?.startDate,
106
- end_date: options?.endDate,
107
- },
108
- });
109
- if (response.error) {
110
- throw new Error(`Get trial balance failed: ${JSON.stringify(response.error)}`);
111
- }
112
- return response.data;
113
- }
114
- /**
115
- * Get mapped trial balance (CoA rolled up to GAAP concepts).
116
- */
117
- async getMappedTrialBalance(graphId, options) {
118
- const response = await (0, sdk_gen_1.getMappedTrialBalance)({
119
- path: { graph_id: graphId },
120
- query: {
121
- mapping_id: options?.mappingId,
122
- start_date: options?.startDate,
123
- end_date: options?.endDate,
124
- },
125
- });
126
- if (response.error) {
127
- throw new Error(`Get mapped trial balance failed: ${JSON.stringify(response.error)}`);
128
- }
129
- return response.data;
82
+ return this.gqlQuery(graphId, graphql_1.GetLedgerTrialBalanceDocument, {
83
+ startDate: options?.startDate ?? null,
84
+ endDate: options?.endDate ?? null,
85
+ }, 'Get trial balance', (data) => data.trialBalance);
130
86
  }
131
- // ── Summary ────────────────────────────────────────────────────────
132
- /**
133
- * Get ledger summary (account count, transaction count, date range).
134
- */
135
- async getSummary(graphId) {
136
- const response = await (0, sdk_gen_1.getLedgerSummary)({
137
- path: { graph_id: graphId },
138
- });
139
- if (response.error) {
140
- throw new Error(`Get summary failed: ${JSON.stringify(response.error)}`);
141
- }
142
- return response.data;
87
+ /** Trial balance rolled up to GAAP reporting concepts via a mapping. */
88
+ async getMappedTrialBalance(graphId, mappingId, options) {
89
+ return this.gqlQuery(graphId, graphql_1.GetLedgerMappedTrialBalanceDocument, {
90
+ mappingId,
91
+ startDate: options?.startDate ?? null,
92
+ endDate: options?.endDate ?? null,
93
+ }, 'Get mapped trial balance', (data) => data.mappedTrialBalance);
143
94
  }
144
95
  // ── Taxonomy ────────────────────────────────────────────────────────
145
- /**
146
- * Get the reporting taxonomy (US GAAP seed).
147
- */
96
+ /** Get the locked US GAAP reporting taxonomy for this graph. */
148
97
  async getReportingTaxonomy(graphId) {
149
- const response = await (0, sdk_gen_1.getReportingTaxonomy)({
150
- path: { graph_id: graphId },
151
- });
152
- if (response.error) {
153
- throw new Error(`Get reporting taxonomy failed: ${JSON.stringify(response.error)}`);
154
- }
155
- return response.data;
98
+ return this.gqlQuery(graphId, graphql_1.GetLedgerReportingTaxonomyDocument, undefined, 'Get reporting taxonomy', (data) => data.reportingTaxonomy);
156
99
  }
157
- /**
158
- * List reporting structures (IS, BS, CF) for a taxonomy.
159
- */
160
- async listStructures(graphId, taxonomyId) {
161
- const response = await (0, sdk_gen_1.listStructures)({
162
- path: { graph_id: graphId },
163
- query: taxonomyId ? { taxonomy_id: taxonomyId } : undefined,
164
- });
165
- if (response.error) {
166
- throw new Error(`List structures failed: ${JSON.stringify(response.error)}`);
167
- }
168
- const data = response.data;
169
- return (data.structures ?? []).map((s) => ({
170
- id: s.id,
171
- name: s.name,
172
- structureType: s.structure_type,
173
- }));
100
+ /** List active taxonomies with optional type filter. */
101
+ async listTaxonomies(graphId, options) {
102
+ const list = await this.gqlQuery(graphId, graphql_1.ListLedgerTaxonomiesDocument, { taxonomyType: options?.taxonomyType ?? null }, 'List taxonomies', (data) => data.taxonomies);
103
+ return list?.taxonomies ?? [];
174
104
  }
175
- /**
176
- * List elements (CoA accounts, GAAP concepts, etc.).
177
- */
105
+ /** Create a new taxonomy (used for CoA + mapping taxonomies). */
106
+ async createTaxonomy(graphId, body) {
107
+ const envelope = await this.callOperation('Create taxonomy', (0, sdk_gen_1.opCreateTaxonomy)({ path: { graph_id: graphId }, body }));
108
+ return (envelope.result ?? {});
109
+ }
110
+ /** List elements (CoA accounts, GAAP concepts, etc.) with filters. */
178
111
  async listElements(graphId, options) {
179
- const response = await (0, sdk_gen_1.listElements)({
180
- path: { graph_id: graphId },
181
- query: {
182
- taxonomy_id: options?.taxonomyId,
183
- source: options?.source,
184
- classification: options?.classification,
185
- is_abstract: options?.isAbstract,
186
- limit: options?.limit,
187
- offset: options?.offset,
188
- },
189
- });
190
- if (response.error) {
191
- throw new Error(`List elements failed: ${JSON.stringify(response.error)}`);
192
- }
193
- return response.data;
112
+ return this.gqlQuery(graphId, graphql_1.ListLedgerElementsDocument, {
113
+ taxonomyId: options?.taxonomyId ?? null,
114
+ source: options?.source ?? null,
115
+ classification: options?.classification ?? null,
116
+ isAbstract: options?.isAbstract ?? null,
117
+ limit: options?.limit ?? 100,
118
+ offset: options?.offset ?? 0,
119
+ }, 'List elements', (data) => data.elements);
194
120
  }
195
- // ── Mappings ────────────────────────────────────────────────────────
196
- /**
197
- * Create a new CoA→GAAP mapping structure.
198
- * Returns the created mapping info.
199
- */
200
- async createMappingStructure(graphId, options) {
201
- const response = await (0, sdk_gen_1.createStructure)({
202
- path: { graph_id: graphId },
203
- body: {
204
- name: options?.name ?? 'CoA to Reporting',
205
- description: options?.description ?? 'Map Chart of Accounts to US GAAP reporting concepts',
206
- structure_type: 'coa_mapping',
207
- taxonomy_id: options?.taxonomyId ?? 'tax_usgaap_reporting',
208
- },
209
- });
210
- if (response.error) {
211
- throw new Error(`Create mapping structure failed: ${JSON.stringify(response.error)}`);
212
- }
213
- const data = response.data;
214
- return {
215
- id: data.id,
216
- name: data.name,
217
- description: data.description ?? null,
218
- structureType: data.structure_type,
219
- taxonomyId: data.taxonomy_id,
220
- isActive: data.is_active ?? true,
221
- };
121
+ /** CoA elements not yet mapped to a reporting concept. */
122
+ async listUnmappedElements(graphId, options) {
123
+ return this.gqlQuery(graphId, graphql_1.ListLedgerUnmappedElementsDocument, { mappingId: options?.mappingId ?? null }, 'List unmapped elements', (data) => data.unmappedElements);
124
+ }
125
+ // ── Structures ──────────────────────────────────────────────────────
126
+ /** List reporting structures (IS, BS, CF, schedules) with optional filters. */
127
+ async listStructures(graphId, options) {
128
+ const list = await this.gqlQuery(graphId, graphql_1.ListLedgerStructuresDocument, {
129
+ taxonomyId: options?.taxonomyId ?? null,
130
+ structureType: options?.structureType ?? null,
131
+ }, 'List structures', (data) => data.structures);
132
+ return list?.structures ?? [];
222
133
  }
223
134
  /**
224
- * List available CoA→GAAP mapping structures.
135
+ * Create a new structure. Most common use is a CoA→reporting mapping
136
+ * structure; also used for custom statement + schedule structures.
225
137
  */
138
+ async createStructure(graphId, body) {
139
+ const envelope = await this.callOperation('Create structure', (0, sdk_gen_1.opCreateStructure)({ path: { graph_id: graphId }, body }));
140
+ return envelope.result;
141
+ }
142
+ // ── Mappings ────────────────────────────────────────────────────────
143
+ /** List active CoA→reporting mapping structures. */
226
144
  async listMappings(graphId) {
227
- const response = await (0, sdk_gen_1.listMappings)({
228
- path: { graph_id: graphId },
229
- });
230
- if (response.error) {
231
- throw new Error(`List mappings failed: ${JSON.stringify(response.error)}`);
232
- }
233
- const data = response.data;
234
- return (data.structures ?? []).map((s) => ({
235
- id: s.id,
236
- name: s.name,
237
- description: s.description ?? null,
238
- structureType: s.structure_type,
239
- taxonomyId: s.taxonomy_id,
240
- isActive: s.is_active ?? true,
241
- }));
145
+ const list = await this.gqlQuery(graphId, graphql_1.ListLedgerMappingsDocument, undefined, 'List mappings', (data) => data.mappings);
146
+ return list?.structures ?? [];
242
147
  }
243
- /**
244
- * Get mapping detail — all associations with element names.
245
- */
246
- async getMappingDetail(graphId, mappingId) {
247
- const response = await (0, sdk_gen_1.getMappingDetail)({
248
- path: { graph_id: graphId, mapping_id: mappingId },
249
- });
250
- if (response.error) {
251
- throw new Error(`Get mapping detail failed: ${JSON.stringify(response.error)}`);
252
- }
253
- return response.data;
148
+ /** Get a mapping structure with all its associations. */
149
+ async getMapping(graphId, mappingId) {
150
+ return this.gqlQuery(graphId, graphql_1.GetLedgerMappingDocument, { mappingId }, 'Get mapping', (data) => data.mapping);
254
151
  }
255
- /**
256
- * Get mapping coverage — how many CoA elements are mapped.
257
- */
152
+ /** Mapping coverage stats — how many CoA elements are mapped. */
258
153
  async getMappingCoverage(graphId, mappingId) {
259
- const response = await (0, sdk_gen_1.getMappingCoverage)({
260
- path: { graph_id: graphId, mapping_id: mappingId },
261
- });
262
- if (response.error) {
263
- throw new Error(`Get mapping coverage failed: ${JSON.stringify(response.error)}`);
264
- }
265
- const data = response.data;
266
- return {
267
- totalCoaElements: data.total_coa_elements ?? 0,
268
- mappedCount: data.mapped_count ?? 0,
269
- unmappedCount: data.unmapped_count ?? 0,
270
- coveragePercent: data.coverage_percent ?? 0,
271
- highConfidence: data.high_confidence ?? 0,
272
- mediumConfidence: data.medium_confidence ?? 0,
273
- lowConfidence: data.low_confidence ?? 0,
274
- };
154
+ return this.gqlQuery(graphId, graphql_1.GetLedgerMappingCoverageDocument, { mappingId }, 'Get mapping coverage', (data) => data.mappingCoverage);
275
155
  }
276
- /**
277
- * Create a manual mapping association (CoA element → GAAP element).
278
- */
279
- async createMapping(graphId, mappingId, fromElementId, toElementId, confidence) {
280
- const response = await (0, sdk_gen_1.createMappingAssociation)({
281
- path: { graph_id: graphId, mapping_id: mappingId },
282
- body: {
283
- from_element_id: fromElementId,
284
- to_element_id: toElementId,
285
- confidence: confidence ?? 1.0,
286
- },
287
- });
288
- if (response.error) {
289
- throw new Error(`Create mapping failed: ${JSON.stringify(response.error)}`);
290
- }
156
+ /** Create a manual mapping association between two elements. */
157
+ async createMappingAssociation(graphId, body) {
158
+ const envelope = await this.callOperation('Create mapping association', (0, sdk_gen_1.opCreateMappingAssociation)({ path: { graph_id: graphId }, body }));
159
+ return (envelope.result ?? {});
291
160
  }
292
- /**
293
- * Delete a mapping association.
294
- */
295
- async deleteMapping(graphId, mappingId, associationId) {
296
- const response = await (0, sdk_gen_1.deleteMappingAssociation)({
297
- path: { graph_id: graphId, mapping_id: mappingId, association_id: associationId },
298
- });
299
- if (response.error) {
300
- throw new Error(`Delete mapping failed: ${JSON.stringify(response.error)}`);
301
- }
161
+ /** Delete a mapping association. */
162
+ async deleteMappingAssociation(graphId, body) {
163
+ const envelope = await this.callOperation('Delete mapping association', (0, sdk_gen_1.opDeleteMappingAssociation)({ path: { graph_id: graphId }, body }));
164
+ return (envelope.result ?? { deleted: true });
302
165
  }
303
166
  /**
304
- * Trigger AI auto-mapping (MappingAgent).
305
- * Returns immediately — the agent runs in the background.
167
+ * Trigger the AI MappingAgent. Returns the operation id — async; the
168
+ * agent runs in the background. Consumers can subscribe to progress
169
+ * via `/v1/operations/{operationId}/stream`.
306
170
  */
307
- async autoMap(graphId, mappingId) {
308
- const response = await (0, sdk_gen_1.autoMapElements)({
309
- path: { graph_id: graphId, mapping_id: mappingId },
310
- });
311
- if (response.error) {
312
- throw new Error(`Auto-map failed: ${JSON.stringify(response.error)}`);
313
- }
314
- const data = response.data;
315
- return {
316
- operationId: data?.operation_id,
317
- };
171
+ async autoMapElements(graphId, body) {
172
+ const envelope = await this.callOperation('Auto-map elements', (0, sdk_gen_1.opAutoMapElements)({ path: { graph_id: graphId }, body }));
173
+ return { operationId: envelope.operationId, status: envelope.status };
318
174
  }
319
175
  // ── Schedules ──────────────────────────────────────────────────────
320
- /**
321
- * Create a schedule with pre-generated monthly facts.
322
- */
176
+ /** List all schedule structures with metadata. */
177
+ async listSchedules(graphId) {
178
+ const list = await this.gqlQuery(graphId, graphql_1.ListLedgerSchedulesDocument, undefined, 'List schedules', (data) => data.schedules);
179
+ return list?.schedules ?? [];
180
+ }
181
+ /** Schedule facts optionally filtered by period window. */
182
+ async getScheduleFacts(graphId, structureId, options) {
183
+ const facts = await this.gqlQuery(graphId, graphql_1.GetLedgerScheduleFactsDocument, {
184
+ structureId,
185
+ periodStart: options?.periodStart ?? null,
186
+ periodEnd: options?.periodEnd ?? null,
187
+ }, 'Get schedule facts', (data) => data.scheduleFacts);
188
+ return facts?.facts ?? [];
189
+ }
190
+ /** Create a new schedule with pre-generated monthly facts. */
323
191
  async createSchedule(graphId, options) {
324
192
  const body = {
325
193
  name: options.name,
@@ -344,153 +212,207 @@ class LedgerClient {
344
212
  }
345
213
  : undefined,
346
214
  };
347
- const response = await (0, sdk_gen_1.createSchedule)({
348
- path: { graph_id: graphId },
349
- body,
350
- });
351
- if (response.error) {
352
- throw new Error(`Create schedule failed: ${JSON.stringify(response.error)}`);
353
- }
354
- const data = response.data;
215
+ const envelope = await this.callOperation('Create schedule', (0, sdk_gen_1.opCreateSchedule)({ path: { graph_id: graphId }, body }));
216
+ const raw = envelope.result;
355
217
  return {
356
- structureId: data.structure_id,
357
- name: data.name,
358
- taxonomyId: data.taxonomy_id,
359
- totalPeriods: data.total_periods,
360
- totalFacts: data.total_facts,
218
+ structureId: raw.structure_id,
219
+ name: raw.name,
220
+ taxonomyId: raw.taxonomy_id,
221
+ totalPeriods: raw.total_periods,
222
+ totalFacts: raw.total_facts,
361
223
  };
362
224
  }
363
- /**
364
- * List all schedules for a graph.
365
- */
366
- async listSchedules(graphId) {
367
- const response = await (0, sdk_gen_1.listSchedules)({
368
- path: { graph_id: graphId },
369
- });
370
- if (response.error) {
371
- throw new Error(`List schedules failed: ${JSON.stringify(response.error)}`);
372
- }
373
- const data = response.data;
374
- return (data.schedules ?? []).map((s) => ({
375
- structureId: s.structure_id,
376
- name: s.name,
377
- taxonomyName: s.taxonomy_name,
378
- entryTemplate: s.entry_template ?? null,
379
- scheduleMetadata: s.schedule_metadata ?? null,
380
- totalPeriods: s.total_periods,
381
- periodsWithEntries: s.periods_with_entries,
382
- }));
383
- }
384
- /**
385
- * Get facts for a schedule, optionally filtered by period.
386
- */
387
- async getScheduleFacts(graphId, structureId, periodStart, periodEnd) {
388
- const response = await (0, sdk_gen_1.getScheduleFacts)({
389
- path: { graph_id: graphId, structure_id: structureId },
390
- query: {
391
- period_start: periodStart ?? null,
392
- period_end: periodEnd ?? null,
393
- },
394
- });
395
- if (response.error) {
396
- throw new Error(`Get schedule facts failed: ${JSON.stringify(response.error)}`);
397
- }
398
- const data = response.data;
399
- return (data.facts ?? []).map((f) => ({
400
- elementId: f.element_id,
401
- elementName: f.element_name,
402
- value: f.value,
403
- periodStart: f.period_start,
404
- periodEnd: f.period_end,
405
- }));
406
- }
407
- /**
408
- * Get close status for all schedules in a fiscal period.
409
- */
410
- async getPeriodCloseStatus(graphId, periodStart, periodEnd) {
411
- const response = await (0, sdk_gen_1.getPeriodCloseStatus)({
412
- path: { graph_id: graphId },
413
- query: { period_start: periodStart, period_end: periodEnd },
414
- });
415
- if (response.error) {
416
- throw new Error(`Get period close status failed: ${JSON.stringify(response.error)}`);
417
- }
418
- const data = response.data;
225
+ /** Truncate a schedule — end it early at `newEndDate`. */
226
+ async truncateSchedule(graphId, structureId, options) {
227
+ const body = {
228
+ structure_id: structureId,
229
+ new_end_date: options.newEndDate,
230
+ reason: options.reason,
231
+ };
232
+ const envelope = await this.callOperation('Truncate schedule', (0, sdk_gen_1.opTruncateSchedule)({ path: { graph_id: graphId }, body }));
233
+ const raw = envelope.result;
419
234
  return {
420
- fiscalPeriodStart: data.fiscal_period_start,
421
- fiscalPeriodEnd: data.fiscal_period_end,
422
- periodStatus: data.period_status,
423
- schedules: (data.schedules ?? []).map((s) => ({
424
- structureId: s.structure_id,
425
- structureName: s.structure_name,
426
- amount: s.amount,
427
- status: s.status,
428
- entryId: s.entry_id ?? null,
429
- })),
430
- totalDraft: data.total_draft,
431
- totalPosted: data.total_posted,
235
+ structureId: raw.structure_id,
236
+ newEndDate: raw.new_end_date,
237
+ factsDeleted: raw.facts_deleted,
238
+ reason: raw.reason,
432
239
  };
433
240
  }
241
+ // ── Period close ────────────────────────────────────────────────────
242
+ /** Close status for all schedules in a fiscal period. */
243
+ async getPeriodCloseStatus(graphId, periodStart, periodEnd) {
244
+ return this.gqlQuery(graphId, graphql_1.GetLedgerPeriodCloseStatusDocument, { periodStart, periodEnd }, 'Get period close status', (data) => data.periodCloseStatus);
245
+ }
246
+ /** All draft entries in a period, fully expanded for review pre-close. */
247
+ async listPeriodDrafts(graphId, period) {
248
+ return this.gqlQuery(graphId, graphql_1.GetLedgerPeriodDraftsDocument, { period }, 'List period drafts', (data) => data.periodDrafts);
249
+ }
434
250
  /**
435
- * Create a draft closing entry from a schedule's facts for a period.
251
+ * Idempotently create (or refresh) a draft closing entry from a
252
+ * schedule for a period. See `ClosingEntryOutcome` for semantics.
436
253
  */
437
254
  async createClosingEntry(graphId, structureId, postingDate, periodStart, periodEnd, memo) {
438
255
  const body = {
256
+ structure_id: structureId,
439
257
  posting_date: postingDate,
440
258
  period_start: periodStart,
441
259
  period_end: periodEnd,
442
260
  memo: memo ?? undefined,
443
261
  };
444
- const response = await (0, sdk_gen_1.createClosingEntry)({
445
- path: { graph_id: graphId, structure_id: structureId },
446
- body,
447
- });
448
- if (response.error) {
449
- throw new Error(`Create closing entry failed: ${JSON.stringify(response.error)}`);
450
- }
451
- const data = response.data;
262
+ const envelope = await this.callOperation('Create closing entry', (0, sdk_gen_1.opCreateClosingEntry)({ path: { graph_id: graphId }, body }));
263
+ return rawToClosingEntry(envelope.result);
264
+ }
265
+ /**
266
+ * Create a manual balanced closing entry (not tied to a schedule).
267
+ * Used for disposals, adjustments, and one-off closing events.
268
+ */
269
+ async createManualClosingEntry(graphId, options) {
270
+ const body = {
271
+ posting_date: options.postingDate,
272
+ memo: options.memo,
273
+ entry_type: options.entryType,
274
+ line_items: options.lineItems.map((li) => ({
275
+ element_id: li.elementId,
276
+ debit_amount: li.debitAmount ?? 0,
277
+ credit_amount: li.creditAmount ?? 0,
278
+ description: li.description ?? null,
279
+ })),
280
+ };
281
+ const envelope = await this.callOperation('Create manual closing entry', (0, sdk_gen_1.opCreateManualClosingEntry)({ path: { graph_id: graphId }, body }));
282
+ return rawToClosingEntry(envelope.result);
283
+ }
284
+ // ── Closing book ───────────────────────────────────────────────────
285
+ /** Grouped closing book structures for the close-screen sidebar. */
286
+ async getClosingBookStructures(graphId) {
287
+ return this.gqlQuery(graphId, graphql_1.GetLedgerClosingBookStructuresDocument, undefined, 'Get closing book structures', (data) => data.closingBookStructures);
288
+ }
289
+ // ── Fiscal Calendar ────────────────────────────────────────────────
290
+ /** Current fiscal calendar state — pointers, gap, closeable status. */
291
+ async getFiscalCalendar(graphId) {
292
+ return this.gqlQuery(graphId, graphql_1.GetLedgerFiscalCalendarDocument, undefined, 'Get fiscal calendar', (data) => data.fiscalCalendar);
293
+ }
294
+ /** One-time ledger initialization — seed fiscal calendar + periods. */
295
+ async initializeLedger(graphId, options) {
296
+ const body = {
297
+ closed_through: options?.closedThrough ?? null,
298
+ fiscal_year_start_month: options?.fiscalYearStartMonth,
299
+ earliest_data_period: options?.earliestDataPeriod ?? null,
300
+ auto_seed_schedules: options?.autoSeedSchedules,
301
+ note: options?.note ?? null,
302
+ };
303
+ const envelope = await this.callOperation('Initialize ledger', (0, sdk_gen_1.opInitializeLedger)({ path: { graph_id: graphId }, body }));
304
+ const raw = envelope.result;
305
+ return {
306
+ fiscalCalendar: rawFiscalCalendarToCamel(raw.fiscal_calendar),
307
+ periodsCreated: raw.periods_created ?? 0,
308
+ warnings: raw.warnings ?? [],
309
+ };
310
+ }
311
+ /** Set the user-controlled close target (YYYY-MM). */
312
+ async setCloseTarget(graphId, period, note) {
313
+ const body = { period, note: note ?? null };
314
+ const envelope = await this.callOperation('Set close target', (0, sdk_gen_1.opSetCloseTarget)({ path: { graph_id: graphId }, body }));
315
+ return rawFiscalCalendarToCamel(envelope.result);
316
+ }
317
+ /** Close a fiscal period — the final commit action. */
318
+ async closePeriod(graphId, period, options) {
319
+ const body = {
320
+ period,
321
+ note: options?.note ?? null,
322
+ allow_stale_sync: options?.allowStaleSync,
323
+ };
324
+ const envelope = await this.callOperation('Close period', (0, sdk_gen_1.opClosePeriod)({ path: { graph_id: graphId }, body }));
325
+ const raw = envelope.result;
452
326
  return {
453
- entryId: data.entry_id,
454
- status: data.status,
455
- postingDate: data.posting_date,
456
- memo: data.memo,
457
- debitElementId: data.debit_element_id,
458
- creditElementId: data.credit_element_id,
459
- amount: data.amount,
327
+ period: raw.period,
328
+ entriesPosted: raw.entries_posted ?? 0,
329
+ targetAutoAdvanced: raw.target_auto_advanced ?? false,
330
+ fiscalCalendar: rawFiscalCalendarToCamel(raw.fiscal_calendar),
331
+ };
332
+ }
333
+ /** Reopen a closed fiscal period. Requires a reason for the audit log. */
334
+ async reopenPeriod(graphId, period, reason, note) {
335
+ const body = {
336
+ period,
337
+ reason,
338
+ note: note ?? null,
460
339
  };
340
+ const envelope = await this.callOperation('Reopen period', (0, sdk_gen_1.opReopenPeriod)({ path: { graph_id: graphId }, body }));
341
+ return rawFiscalCalendarToCamel(envelope.result);
461
342
  }
462
- // ── Closing Book ─────────────────────────────────────────────────────
343
+ // Reports, statements, and publish lists live on `ReportClient`.
344
+ // ── Internal helpers ────────────────────────────────────────────────
463
345
  /**
464
- * Get all closing book structure categories for the sidebar.
465
- * Returns statements, account rollups, schedules, trial balance,
466
- * and period close grouped into categories.
346
+ * Run a typed GraphQL query against the per-graph endpoint and
347
+ * translate ClientError into a readable facade error.
467
348
  */
468
- async getClosingBookStructures(graphId) {
469
- const response = await (0, sdk_gen_1.getClosingBookStructures)({
470
- path: { graph_id: graphId },
471
- });
472
- if (response.error) {
473
- throw new Error(`Get closing book structures failed: ${JSON.stringify(response.error)}`);
349
+ async gqlQuery(graphId, document, variables, label, pick) {
350
+ try {
351
+ const client = this.gql.get(graphId);
352
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
353
+ const raw = client.request;
354
+ // graphql-request's overloads don't cleanly resolve for generic
355
+ // helpers wrapping codegen's `Exact<>` var types, so we bypass
356
+ // the typed overload with a narrow cast of `request` itself.
357
+ const data = (await raw.call(client, document, variables));
358
+ return pick(data);
359
+ }
360
+ catch (err) {
361
+ if (err instanceof graphql_request_1.ClientError) {
362
+ throw new Error(`${label} failed: ${JSON.stringify(err.response.errors ?? err.message)}`);
363
+ }
364
+ throw err;
474
365
  }
475
- return response.data;
476
366
  }
477
367
  /**
478
- * Get account rollups CoA accounts grouped by reporting element with balances.
479
- * Shows how company-specific accounts roll up to standardized reporting lines.
368
+ * Await an SDK-generated `opXxx(...)` call, throw a readable error on
369
+ * non-2xx, and return the `OperationEnvelope` on success.
480
370
  */
481
- async getAccountRollups(graphId, options) {
482
- const response = await (0, sdk_gen_1.getAccountRollups)({
483
- path: { graph_id: graphId },
484
- query: {
485
- mapping_id: options?.mappingId,
486
- start_date: options?.startDate,
487
- end_date: options?.endDate,
488
- },
489
- });
490
- if (response.error) {
491
- throw new Error(`Get account rollups failed: ${JSON.stringify(response.error)}`);
371
+ async callOperation(label, call) {
372
+ const response = await call;
373
+ if (response.error !== undefined) {
374
+ throw new Error(`${label} failed: ${JSON.stringify(response.error)}`);
375
+ }
376
+ if (response.data === undefined) {
377
+ throw new Error(`${label} failed: empty response`);
492
378
  }
493
379
  return response.data;
494
380
  }
495
381
  }
496
382
  exports.LedgerClient = LedgerClient;
383
+ // ── Module-private conversion helpers ─────────────────────────────────
384
+ function rawToClosingEntry(data) {
385
+ return {
386
+ outcome: data.outcome,
387
+ entryId: data.entry_id ?? null,
388
+ status: data.status ?? null,
389
+ postingDate: data.posting_date ?? null,
390
+ memo: data.memo ?? null,
391
+ debitElementId: data.debit_element_id ?? null,
392
+ creditElementId: data.credit_element_id ?? null,
393
+ amount: data.amount ?? null,
394
+ reason: data.reason ?? null,
395
+ };
396
+ }
397
+ function rawFiscalCalendarToCamel(raw) {
398
+ return {
399
+ graphId: raw.graph_id,
400
+ fiscalYearStartMonth: raw.fiscal_year_start_month,
401
+ closedThrough: raw.closed_through ?? null,
402
+ closeTarget: raw.close_target ?? null,
403
+ gapPeriods: raw.gap_periods ?? 0,
404
+ catchUpSequence: raw.catch_up_sequence ?? [],
405
+ closeableNow: raw.closeable_now ?? false,
406
+ blockers: raw.blockers ?? [],
407
+ lastCloseAt: raw.last_close_at ?? null,
408
+ initializedAt: raw.initialized_at ?? null,
409
+ lastSyncAt: raw.last_sync_at ?? null,
410
+ periods: (raw.periods ?? []).map((p) => ({
411
+ name: p.name,
412
+ startDate: p.start_date,
413
+ endDate: p.end_date,
414
+ status: p.status,
415
+ closedAt: p.closed_at ?? null,
416
+ })),
417
+ };
418
+ }