@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
@@ -1,432 +0,0 @@
1
- import { beforeEach, describe, expect, it, vi } from 'vitest'
2
- import { QueryClient, QueuedQueryError } from './QueryClient'
3
-
4
- // Helper to create proper mock Response objects
5
- function createMockResponse(data: any, options: { ok?: boolean; status?: number } = {}) {
6
- return {
7
- ok: options.ok ?? true,
8
- status: options.status ?? 200,
9
- statusText: options.status === 200 ? 'OK' : 'Error',
10
- headers: new Headers({ 'content-type': 'application/json' }),
11
- json: async () => data,
12
- text: async () => JSON.stringify(data),
13
- blob: async () => new Blob([JSON.stringify(data)]),
14
- arrayBuffer: async () => new TextEncoder().encode(JSON.stringify(data)).buffer,
15
- }
16
- }
17
-
18
- describe('QueryClient', () => {
19
- let queryClient: QueryClient
20
- let mockFetch: any
21
-
22
- beforeEach(() => {
23
- queryClient = new QueryClient({
24
- baseUrl: 'http://localhost:8000',
25
- headers: { 'X-API-Key': 'test-key' },
26
- })
27
-
28
- // Mock global fetch (also set globalThis for SDK client compatibility)
29
- mockFetch = vi.fn()
30
- global.fetch = mockFetch
31
- globalThis.fetch = mockFetch
32
-
33
- // Reset all mocks
34
- vi.clearAllMocks()
35
- })
36
-
37
- describe('executeQuery - immediate response', () => {
38
- it('should execute a sync query successfully', async () => {
39
- mockFetch.mockResolvedValueOnce(
40
- createMockResponse({
41
- data: [
42
- { name: 'Alice', age: 30 },
43
- { name: 'Bob', age: 25 },
44
- ],
45
- columns: ['name', 'age'],
46
- row_count: 2,
47
- execution_time_ms: 45,
48
- timestamp: '2025-01-01T00:00:00Z',
49
- })
50
- )
51
-
52
- const result = await queryClient.executeQuery('graph_123', {
53
- query: 'MATCH (n:Person) RETURN n.name, n.age',
54
- })
55
-
56
- // Should be a QueryResult, not an iterator
57
- expect(result).toHaveProperty('data')
58
- expect(result).toHaveProperty('columns')
59
-
60
- const queryResult = result as any
61
- expect(queryResult.data).toHaveLength(2)
62
- expect(queryResult.columns).toEqual(['name', 'age'])
63
- expect(queryResult.row_count).toBe(2)
64
- expect(queryResult.execution_time_ms).toBe(45)
65
- expect(queryResult.graph_id).toBe('graph_123')
66
- })
67
-
68
- it('should handle query with parameters', async () => {
69
- mockFetch.mockResolvedValueOnce(
70
- createMockResponse({
71
- data: [{ name: 'Alice' }],
72
- columns: ['name'],
73
- row_count: 1,
74
- execution_time_ms: 20,
75
- })
76
- )
77
-
78
- const result = await queryClient.executeQuery(
79
- 'graph_123',
80
- {
81
- query: 'MATCH (n:Person {age: $age}) RETURN n.name',
82
- parameters: { age: 30 },
83
- },
84
- { mode: 'sync' }
85
- )
86
-
87
- const queryResult = result as any
88
- expect(queryResult.data).toHaveLength(1)
89
- expect(queryResult.data[0].name).toBe('Alice')
90
- })
91
-
92
- it('should default row_count if not provided', async () => {
93
- mockFetch.mockResolvedValueOnce(
94
- createMockResponse({
95
- data: [{ a: 1 }, { b: 2 }, { c: 3 }],
96
- columns: ['value'],
97
- })
98
- )
99
-
100
- const result = await queryClient.executeQuery('graph_123', {
101
- query: 'RETURN 1',
102
- })
103
-
104
- const queryResult = result as any
105
- expect(queryResult.row_count).toBe(3) // Should default to data.length
106
- })
107
-
108
- it('should default execution_time_ms if not provided', async () => {
109
- mockFetch.mockResolvedValueOnce(
110
- createMockResponse({
111
- data: [],
112
- columns: [],
113
- })
114
- )
115
-
116
- const result = await queryClient.executeQuery('graph_123', {
117
- query: 'RETURN 1',
118
- })
119
-
120
- const queryResult = result as any
121
- expect(queryResult.execution_time_ms).toBe(0)
122
- })
123
- })
124
-
125
- describe('executeQuery - queued response', () => {
126
- it('should throw QueuedQueryError when maxWait is 0', async () => {
127
- mockFetch.mockResolvedValueOnce(
128
- createMockResponse({
129
- status: 'queued',
130
- operation_id: 'op_123',
131
- queue_position: 5,
132
- estimated_wait_seconds: 30,
133
- message: 'Query queued',
134
- })
135
- )
136
-
137
- await expect(
138
- queryClient.executeQuery(
139
- 'graph_123',
140
- { query: 'RETURN 1' },
141
- { maxWait: 0 } // Don't wait for queued queries
142
- )
143
- ).rejects.toThrow(QueuedQueryError)
144
- })
145
-
146
- it('should call onQueueUpdate when query is queued', async () => {
147
- mockFetch.mockResolvedValueOnce(
148
- createMockResponse({
149
- status: 'queued',
150
- operation_id: 'op_123',
151
- queue_position: 3,
152
- estimated_wait_seconds: 15,
153
- message: 'Query queued',
154
- })
155
- )
156
-
157
- const queueUpdates: Array<{ position: number; wait: number }> = []
158
-
159
- try {
160
- await queryClient.executeQuery(
161
- 'graph_123',
162
- { query: 'RETURN 1' },
163
- {
164
- maxWait: 0,
165
- onQueueUpdate: (position, estimatedWait) => {
166
- queueUpdates.push({ position, wait: estimatedWait })
167
- },
168
- }
169
- )
170
- } catch (error) {
171
- // Expected to throw QueuedQueryError
172
- expect(error).toBeInstanceOf(QueuedQueryError)
173
- expect((error as QueuedQueryError).queueInfo.queue_position).toBe(3)
174
- }
175
-
176
- expect(queueUpdates).toHaveLength(1)
177
- expect(queueUpdates[0].position).toBe(3)
178
- expect(queueUpdates[0].wait).toBe(15)
179
- })
180
- })
181
-
182
- describe('executeQuery - error handling', () => {
183
- it('should throw error for unexpected response format', async () => {
184
- mockFetch.mockResolvedValueOnce(
185
- createMockResponse({
186
- unexpected: 'format',
187
- })
188
- )
189
-
190
- await expect(queryClient.executeQuery('graph_123', { query: 'RETURN 1' })).rejects.toThrow(
191
- 'Unexpected response format'
192
- )
193
- })
194
-
195
- it('should handle fetch errors', async () => {
196
- mockFetch.mockRejectedValueOnce(new Error('Network error'))
197
-
198
- await expect(queryClient.executeQuery('graph_123', { query: 'RETURN 1' })).rejects.toThrow(
199
- 'Network error'
200
- )
201
- })
202
- })
203
-
204
- describe('query (convenience method)', () => {
205
- it('should execute a simple query', async () => {
206
- mockFetch.mockResolvedValueOnce(
207
- createMockResponse({
208
- data: [{ result: 42 }],
209
- columns: ['result'],
210
- row_count: 1,
211
- execution_time_ms: 10,
212
- })
213
- )
214
-
215
- const result = await queryClient.query('graph_123', 'RETURN 42 as result')
216
-
217
- expect(result.data).toHaveLength(1)
218
- expect(result.data[0].result).toBe(42)
219
- })
220
-
221
- it('should execute query with parameters', async () => {
222
- mockFetch.mockResolvedValueOnce(
223
- createMockResponse({
224
- data: [{ sum: 10 }],
225
- columns: ['sum'],
226
- row_count: 1,
227
- execution_time_ms: 5,
228
- })
229
- )
230
-
231
- const result = await queryClient.query('graph_123', 'RETURN $a + $b as sum', {
232
- a: 3,
233
- b: 7,
234
- })
235
-
236
- expect(result.data[0].sum).toBe(10)
237
- })
238
- })
239
-
240
- describe('executeQuery - stream mode with NDJSON', () => {
241
- it('should parse NDJSON streaming response', async () => {
242
- const ndjsonBody = [
243
- '{"columns":["name","age"],"rows":[["Alice",30],["Bob",25]]}',
244
- '{"rows":[["Charlie",35]]}',
245
- '',
246
- ].join('\n')
247
-
248
- // Create a ReadableStream from the NDJSON string
249
- const stream = new ReadableStream({
250
- start(controller) {
251
- controller.enqueue(new TextEncoder().encode(ndjsonBody))
252
- controller.close()
253
- },
254
- })
255
-
256
- const mockStreamResponse = {
257
- data: undefined,
258
- error: undefined,
259
- response: {
260
- ok: true,
261
- status: 200,
262
- headers: new Headers({ 'content-type': 'application/x-ndjson' }),
263
- body: stream,
264
- json: async () => ({}),
265
- },
266
- }
267
-
268
- // Mock the SDK function via fetch
269
- mockFetch.mockResolvedValueOnce({
270
- ok: true,
271
- status: 200,
272
- headers: new Headers({ 'content-type': 'application/x-ndjson' }),
273
- body: stream,
274
- json: async () => mockStreamResponse,
275
- text: async () => JSON.stringify(mockStreamResponse),
276
- })
277
-
278
- // We can't easily test the full stream mode through the SDK mock
279
- // because the SDK parses the response. Test the NDJSON parser directly instead.
280
- const parser = (queryClient as any).parseNDJSONResponse.bind(queryClient)
281
-
282
- const ndjsonStream = new ReadableStream({
283
- start(controller) {
284
- controller.enqueue(
285
- new TextEncoder().encode(
286
- '{"columns":["name"],"rows":[["Alice"],["Bob"]]}\n{"rows":[["Charlie"]]}\n'
287
- )
288
- )
289
- controller.close()
290
- },
291
- })
292
-
293
- const mockResp = {
294
- body: ndjsonStream,
295
- headers: new Headers({ 'content-type': 'application/x-ndjson' }),
296
- }
297
-
298
- const result = await parser(mockResp, 'graph_1')
299
-
300
- expect(result.columns).toEqual(['name'])
301
- expect(result.data).toEqual([['Alice'], ['Bob'], ['Charlie']])
302
- expect(result.row_count).toBe(3)
303
- expect(result.graph_id).toBe('graph_1')
304
- })
305
-
306
- it('should handle NDJSON with data key instead of rows', async () => {
307
- const parser = (queryClient as any).parseNDJSONResponse.bind(queryClient)
308
-
309
- const stream = new ReadableStream({
310
- start(controller) {
311
- controller.enqueue(
312
- new TextEncoder().encode(
313
- '{"columns":["id"],"data":[{"id":1},{"id":2}],"execution_time_ms":50}\n'
314
- )
315
- )
316
- controller.close()
317
- },
318
- })
319
-
320
- const result = await parser({ body: stream }, 'graph_1')
321
-
322
- expect(result.data).toEqual([{ id: 1 }, { id: 2 }])
323
- expect(result.row_count).toBe(2)
324
- expect(result.execution_time_ms).toBe(50)
325
- })
326
-
327
- it('should throw on NDJSON parse errors', async () => {
328
- const parser = (queryClient as any).parseNDJSONResponse.bind(queryClient)
329
-
330
- const stream = new ReadableStream({
331
- start(controller) {
332
- controller.enqueue(new TextEncoder().encode('not valid json\n'))
333
- controller.close()
334
- },
335
- })
336
-
337
- await expect(parser({ body: stream }, 'graph_1')).rejects.toThrow('NDJSON parsing failed')
338
- })
339
-
340
- it('should throw when body is not readable', async () => {
341
- const parser = (queryClient as any).parseNDJSONResponse.bind(queryClient)
342
-
343
- await expect(parser({ body: null }, 'graph_1')).rejects.toThrow(
344
- 'Response body is not readable'
345
- )
346
- })
347
-
348
- it('should track max execution_time_ms across chunks', async () => {
349
- const parser = (queryClient as any).parseNDJSONResponse.bind(queryClient)
350
-
351
- const stream = new ReadableStream({
352
- start(controller) {
353
- controller.enqueue(
354
- new TextEncoder().encode(
355
- '{"columns":["x"],"rows":[[1]],"execution_time_ms":10}\n' +
356
- '{"rows":[[2]],"execution_time_ms":50}\n' +
357
- '{"rows":[[3]],"execution_time_ms":25}\n'
358
- )
359
- )
360
- controller.close()
361
- },
362
- })
363
-
364
- const result = await parser({ body: stream }, 'graph_1')
365
-
366
- expect(result.execution_time_ms).toBe(50) // max across chunks
367
- expect(result.row_count).toBe(3)
368
- })
369
- })
370
-
371
- describe('streamQuery', () => {
372
- it('should yield all data items when result is non-streaming', async () => {
373
- mockFetch.mockResolvedValueOnce(
374
- createMockResponse({
375
- data: [{ id: 1 }, { id: 2 }, { id: 3 }],
376
- columns: ['id'],
377
- row_count: 3,
378
- execution_time_ms: 10,
379
- })
380
- )
381
-
382
- const items: any[] = []
383
- for await (const item of queryClient.streamQuery('graph_1', 'MATCH (n) RETURN n')) {
384
- items.push(item)
385
- }
386
-
387
- expect(items).toEqual([{ id: 1 }, { id: 2 }, { id: 3 }])
388
- })
389
- })
390
-
391
- describe('close', () => {
392
- it('should close without error when no SSE client exists', () => {
393
- expect(() => queryClient.close()).not.toThrow()
394
- })
395
-
396
- it('should be safe to call multiple times', () => {
397
- queryClient.close()
398
- expect(() => queryClient.close()).not.toThrow()
399
- })
400
- })
401
-
402
- describe('QueuedQueryError', () => {
403
- it('should create error with queue info', () => {
404
- const queueInfo = {
405
- status: 'queued' as const,
406
- operation_id: 'op_123',
407
- queue_position: 5,
408
- estimated_wait_seconds: 30,
409
- message: 'Query queued',
410
- }
411
-
412
- const error = new QueuedQueryError(queueInfo)
413
-
414
- expect(error.message).toBe('Query was queued')
415
- expect(error.name).toBe('QueuedQueryError')
416
- expect(error.queueInfo).toEqual(queueInfo)
417
- })
418
-
419
- it('should be instanceof Error', () => {
420
- const error = new QueuedQueryError({
421
- status: 'queued',
422
- operation_id: 'op_1',
423
- queue_position: 1,
424
- estimated_wait_seconds: 5,
425
- message: 'Queued',
426
- })
427
-
428
- expect(error).toBeInstanceOf(Error)
429
- expect(error).toBeInstanceOf(QueuedQueryError)
430
- })
431
- })
432
- })