@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,375 +0,0 @@
1
- import { beforeEach, describe, expect, it, vi } from 'vitest'
2
- import { EventType, SSEClient } from './SSEClient'
3
-
4
- // Mock EventSource for testing
5
- class MockEventSource {
6
- url: string
7
- withCredentials: boolean
8
- readyState: number = 0 // 0 = CONNECTING, 1 = OPEN, 2 = CLOSED
9
- onopen: ((event: any) => void) | null = null
10
- onerror: ((event: any) => void) | null = null
11
- onmessage: ((event: any) => void) | null = null
12
- private eventListeners: Map<string, Set<(event: any) => void>> = new Map()
13
-
14
- static CONNECTING = 0
15
- static OPEN = 1
16
- static CLOSED = 2
17
-
18
- constructor(url: string, options?: { withCredentials?: boolean }) {
19
- this.url = url
20
- this.withCredentials = options?.withCredentials ?? false
21
-
22
- // Simulate async connection
23
- setTimeout(() => {
24
- this.readyState = MockEventSource.OPEN
25
- if (this.onopen) {
26
- this.onopen({ type: 'open' })
27
- }
28
- }, 0)
29
- }
30
-
31
- addEventListener(event: string, listener: (event: any) => void) {
32
- if (!this.eventListeners.has(event)) {
33
- this.eventListeners.set(event, new Set())
34
- }
35
- this.eventListeners.get(event)!.add(listener)
36
- }
37
-
38
- removeEventListener(event: string, listener: (event: any) => void) {
39
- const listeners = this.eventListeners.get(event)
40
- if (listeners) {
41
- listeners.delete(listener)
42
- }
43
- }
44
-
45
- dispatchEvent(event: any) {
46
- const listeners = this.eventListeners.get(event.type)
47
- if (listeners) {
48
- listeners.forEach((listener) => listener(event))
49
- }
50
- return true
51
- }
52
-
53
- close() {
54
- this.readyState = MockEventSource.CLOSED
55
- }
56
-
57
- // Test helper to simulate receiving a message
58
- simulateMessage(eventType: string, data: any, lastEventId?: string) {
59
- const event = {
60
- type: eventType,
61
- data: JSON.stringify(data),
62
- lastEventId: lastEventId || '',
63
- }
64
-
65
- if (eventType === 'message' && this.onmessage) {
66
- this.onmessage(event)
67
- } else {
68
- const listeners = this.eventListeners.get(eventType)
69
- if (listeners) {
70
- listeners.forEach((listener) => listener(event))
71
- }
72
- }
73
- }
74
-
75
- // Test helper to simulate error
76
- simulateError() {
77
- if (this.onerror) {
78
- this.onerror({ type: 'error' })
79
- }
80
- }
81
- }
82
-
83
- describe('SSEClient', () => {
84
- let mockEventSource: MockEventSource
85
-
86
- beforeEach(() => {
87
- // Mock global EventSource
88
- global.EventSource = MockEventSource as any
89
- vi.clearAllMocks()
90
- })
91
-
92
- describe('connect', () => {
93
- it('should connect to SSE endpoint successfully', async () => {
94
- const client = new SSEClient({
95
- baseUrl: 'http://localhost:8000',
96
- })
97
-
98
- await expect(client.connect('op_123')).resolves.toBeUndefined()
99
- expect(client.isConnected()).toBe(true)
100
- })
101
-
102
- it('should include token in URL when provided', async () => {
103
- const client = new SSEClient({
104
- baseUrl: 'http://localhost:8000',
105
- token: 'my-jwt-token',
106
- })
107
-
108
- await client.connect('op_123')
109
-
110
- // We can't directly access the EventSource URL in this mock,
111
- // but the client should have connected successfully
112
- expect(client.isConnected()).toBe(true)
113
- })
114
-
115
- it('should include from_sequence parameter', async () => {
116
- const client = new SSEClient({
117
- baseUrl: 'http://localhost:8000',
118
- })
119
-
120
- await client.connect('op_123', 42)
121
- expect(client.isConnected()).toBe(true)
122
- })
123
-
124
- it('should set withCredentials when credentials is include', async () => {
125
- const client = new SSEClient({
126
- baseUrl: 'http://localhost:8000',
127
- credentials: 'include',
128
- })
129
-
130
- await client.connect('op_123')
131
- expect(client.isConnected()).toBe(true)
132
- })
133
- })
134
-
135
- describe('event handling', () => {
136
- it('should emit connected event on connection', async () => {
137
- const client = new SSEClient({
138
- baseUrl: 'http://localhost:8000',
139
- })
140
-
141
- const connectedEvents: any[] = []
142
- client.on('connected', (data) => connectedEvents.push(data))
143
-
144
- await client.connect('op_123')
145
-
146
- expect(connectedEvents).toHaveLength(1)
147
- })
148
-
149
- it('should handle typed events', async () => {
150
- const client = new SSEClient({
151
- baseUrl: 'http://localhost:8000',
152
- })
153
-
154
- const progressEvents: any[] = []
155
- client.on(EventType.OPERATION_PROGRESS, (data) => progressEvents.push(data))
156
-
157
- await client.connect('op_123')
158
-
159
- // Simulate receiving a progress event
160
- const eventSource = (client as any).eventSource as MockEventSource
161
- eventSource.simulateMessage(EventType.OPERATION_PROGRESS, {
162
- message: 'Processing...',
163
- progress_percent: 50,
164
- })
165
-
166
- expect(progressEvents).toHaveLength(1)
167
- expect(progressEvents[0].message).toBe('Processing...')
168
- expect(progressEvents[0].progress_percent).toBe(50)
169
- })
170
-
171
- it('should auto-close on completion events', async () => {
172
- const client = new SSEClient({
173
- baseUrl: 'http://localhost:8000',
174
- })
175
-
176
- await client.connect('op_123')
177
-
178
- const eventSource = (client as any).eventSource as MockEventSource
179
- eventSource.simulateMessage(EventType.OPERATION_COMPLETED, {
180
- result: { success: true },
181
- })
182
-
183
- // Client should close automatically
184
- expect(client.isConnected()).toBe(false)
185
- })
186
-
187
- it('should auto-close on error events', async () => {
188
- const client = new SSEClient({
189
- baseUrl: 'http://localhost:8000',
190
- })
191
-
192
- await client.connect('op_123')
193
-
194
- const eventSource = (client as any).eventSource as MockEventSource
195
- eventSource.simulateMessage(EventType.OPERATION_ERROR, {
196
- error: 'Something failed',
197
- })
198
-
199
- expect(client.isConnected()).toBe(false)
200
- })
201
-
202
- it('should auto-close on cancelled events', async () => {
203
- const client = new SSEClient({
204
- baseUrl: 'http://localhost:8000',
205
- })
206
-
207
- await client.connect('op_123')
208
-
209
- const eventSource = (client as any).eventSource as MockEventSource
210
- eventSource.simulateMessage(EventType.OPERATION_CANCELLED, {
211
- message: 'Cancelled by user',
212
- })
213
-
214
- expect(client.isConnected()).toBe(false)
215
- })
216
-
217
- it('should handle heartbeat events', async () => {
218
- const client = new SSEClient({
219
- baseUrl: 'http://localhost:8000',
220
- })
221
-
222
- const heartbeats: any[] = []
223
- client.on(EventType.HEARTBEAT, (data) => heartbeats.push(data))
224
-
225
- await client.connect('op_123')
226
-
227
- const eventSource = (client as any).eventSource as MockEventSource
228
- eventSource.simulateMessage(EventType.HEARTBEAT, { timestamp: Date.now() })
229
-
230
- expect(heartbeats).toHaveLength(1)
231
- })
232
-
233
- it('should handle data chunk events', async () => {
234
- const client = new SSEClient({
235
- baseUrl: 'http://localhost:8000',
236
- })
237
-
238
- const chunks: any[] = []
239
- client.on(EventType.DATA_CHUNK, (data) => chunks.push(data))
240
-
241
- await client.connect('op_123')
242
-
243
- const eventSource = (client as any).eventSource as MockEventSource
244
- eventSource.simulateMessage(EventType.DATA_CHUNK, {
245
- rows: [
246
- { id: 1, name: 'Alice' },
247
- { id: 2, name: 'Bob' },
248
- ],
249
- })
250
-
251
- expect(chunks).toHaveLength(1)
252
- expect(chunks[0].rows).toHaveLength(2)
253
- })
254
- })
255
-
256
- describe('listener management', () => {
257
- it('should add and remove listeners', async () => {
258
- const client = new SSEClient({
259
- baseUrl: 'http://localhost:8000',
260
- })
261
-
262
- const events: any[] = []
263
- const listener = (data: any) => events.push(data)
264
-
265
- client.on('test-event', listener)
266
- await client.connect('op_123')
267
-
268
- // Manually emit an event
269
- ;(client as any).emit('test-event', { value: 1 })
270
- expect(events).toHaveLength(1)
271
-
272
- // Remove listener
273
- client.off('test-event', listener)
274
- ;(client as any).emit('test-event', { value: 2 })
275
- expect(events).toHaveLength(1) // Should not have increased
276
- })
277
-
278
- it('should support multiple listeners for same event', async () => {
279
- const client = new SSEClient({
280
- baseUrl: 'http://localhost:8000',
281
- })
282
-
283
- const events1: any[] = []
284
- const events2: any[] = []
285
-
286
- client.on('test-event', (data) => events1.push(data))
287
- client.on('test-event', (data) => events2.push(data))
288
-
289
- await client.connect('op_123')
290
- ;(client as any).emit('test-event', { value: 1 })
291
-
292
- expect(events1).toHaveLength(1)
293
- expect(events2).toHaveLength(1)
294
- })
295
- })
296
-
297
- describe('close', () => {
298
- it('should close the connection', async () => {
299
- const client = new SSEClient({
300
- baseUrl: 'http://localhost:8000',
301
- })
302
-
303
- await client.connect('op_123')
304
- expect(client.isConnected()).toBe(true)
305
-
306
- client.close()
307
- expect(client.isConnected()).toBe(false)
308
- })
309
-
310
- it('should emit closed event', async () => {
311
- const client = new SSEClient({
312
- baseUrl: 'http://localhost:8000',
313
- })
314
-
315
- const closedEvents: any[] = []
316
- client.on('closed', (data) => closedEvents.push(data))
317
-
318
- await client.connect('op_123')
319
- client.close()
320
-
321
- expect(closedEvents).toHaveLength(1)
322
- })
323
-
324
- it('should clear all listeners on close', async () => {
325
- const client = new SSEClient({
326
- baseUrl: 'http://localhost:8000',
327
- })
328
-
329
- const events: any[] = []
330
- client.on('test-event', (data) => events.push(data))
331
-
332
- await client.connect('op_123')
333
- client.close()
334
-
335
- // Try to emit after close - should not receive events
336
- ;(client as any).emit('test-event', { value: 1 })
337
- expect(events).toHaveLength(0)
338
- })
339
-
340
- it('should be safe to call close multiple times', async () => {
341
- const client = new SSEClient({
342
- baseUrl: 'http://localhost:8000',
343
- })
344
-
345
- await client.connect('op_123')
346
-
347
- client.close()
348
- expect(() => client.close()).not.toThrow()
349
- })
350
- })
351
-
352
- describe('configuration', () => {
353
- it('should accept all config options', () => {
354
- const client = new SSEClient({
355
- baseUrl: 'http://localhost:8000',
356
- credentials: 'include',
357
- headers: { 'X-Custom': 'value' },
358
- token: 'jwt-token',
359
- maxRetries: 5,
360
- retryDelay: 2000,
361
- heartbeatInterval: 60000,
362
- })
363
-
364
- expect(client).toBeInstanceOf(SSEClient)
365
- })
366
-
367
- it('should use default config values', () => {
368
- const client = new SSEClient({
369
- baseUrl: 'http://localhost:8000',
370
- })
371
-
372
- expect(client).toBeInstanceOf(SSEClient)
373
- })
374
- })
375
- })
@@ -1,210 +0,0 @@
1
- 'use client'
2
-
3
- /**
4
- * Core SSE (Server-Sent Events) client for RoboSystems API
5
- * Provides automatic reconnection, event replay, and type-safe event handling
6
- *
7
- * SECURITY NOTE: When using JWT authentication, tokens are passed as query parameters
8
- * due to EventSource API limitations. This means tokens may appear in:
9
- * - Server access logs
10
- * - Proxy logs
11
- * - Browser history
12
- * - Referer headers
13
- *
14
- * For production environments with sensitive data, consider:
15
- * - Using cookie-based authentication instead
16
- * - Implementing a WebSocket-based alternative
17
- * - Using short-lived tokens that expire quickly
18
- * - Ensuring all connections use HTTPS
19
- */
20
-
21
- export interface SSEConfig {
22
- baseUrl: string
23
- credentials?: 'include' | 'same-origin' | 'omit'
24
- headers?: Record<string, string>
25
- token?: string // JWT token for authentication
26
- maxRetries?: number
27
- retryDelay?: number
28
- heartbeatInterval?: number
29
- }
30
-
31
- export interface SSEEvent {
32
- event: string
33
- data: any
34
- id?: string
35
- retry?: number
36
- timestamp: Date
37
- }
38
-
39
- export enum EventType {
40
- OPERATION_STARTED = 'operation_started',
41
- OPERATION_PROGRESS = 'operation_progress',
42
- OPERATION_COMPLETED = 'operation_completed',
43
- OPERATION_ERROR = 'operation_error',
44
- OPERATION_CANCELLED = 'operation_cancelled',
45
- DATA_CHUNK = 'data_chunk',
46
- METADATA = 'metadata',
47
- HEARTBEAT = 'heartbeat',
48
- QUEUE_UPDATE = 'queue_update',
49
- }
50
-
51
- export class SSEClient {
52
- private config: SSEConfig
53
- private eventSource?: EventSource
54
- private reconnectAttempts: number = 0
55
- private lastEventId?: string
56
- private closed: boolean = false
57
- private listeners: Map<string, Set<(data: any) => void>> = new Map()
58
-
59
- constructor(config: SSEConfig) {
60
- this.config = {
61
- maxRetries: 5,
62
- retryDelay: 1000,
63
- heartbeatInterval: 30000,
64
- ...config,
65
- }
66
- }
67
-
68
- async connect(operationId: string, fromSequence: number = 0): Promise<void> {
69
- return new Promise((resolve, reject) => {
70
- let url = `${this.config.baseUrl}/v1/operations/${operationId}/stream?from_sequence=${fromSequence}`
71
-
72
- // Add JWT token as query parameter if provided
73
- // WARNING: EventSource API doesn't support custom headers, so tokens are passed via query param
74
- // This has security implications - see class documentation
75
- if (this.config.token) {
76
- url += `&token=${encodeURIComponent(this.config.token)}`
77
- }
78
-
79
- this.eventSource = new EventSource(url, {
80
- withCredentials: this.config.credentials === 'include',
81
- } as any)
82
-
83
- const connectionTimeout = setTimeout(() => {
84
- reject(new Error('Connection timeout'))
85
- this.close()
86
- }, 10000)
87
-
88
- this.eventSource.onopen = () => {
89
- clearTimeout(connectionTimeout)
90
- this.reconnectAttempts = 0
91
- this.emit('connected', null)
92
- resolve()
93
- }
94
-
95
- this.eventSource.onerror = (error) => {
96
- clearTimeout(connectionTimeout)
97
- if (!this.closed) {
98
- this.handleError(error, operationId, fromSequence)
99
- }
100
- }
101
-
102
- this.eventSource.onmessage = (event) => {
103
- this.handleMessage(event)
104
- }
105
-
106
- // Set up specific event listeners
107
- Object.values(EventType).forEach((eventType) => {
108
- this.eventSource!.addEventListener(eventType, (event: any) => {
109
- this.handleTypedEvent(eventType, event)
110
- })
111
- })
112
- })
113
- }
114
-
115
- private handleMessage(event: MessageEvent): void {
116
- try {
117
- const data = JSON.parse(event.data)
118
- const sseEvent: SSEEvent = {
119
- event: event.type || 'message',
120
- data,
121
- id: event.lastEventId,
122
- timestamp: new Date(),
123
- }
124
-
125
- this.lastEventId = event.lastEventId
126
- this.emit('event', sseEvent)
127
- } catch (error) {
128
- this.emit('parse_error', { error, rawData: event.data })
129
- }
130
- }
131
-
132
- private handleTypedEvent(eventType: string, event: MessageEvent): void {
133
- try {
134
- const data = JSON.parse(event.data)
135
- this.lastEventId = event.lastEventId
136
- this.emit(eventType, data)
137
-
138
- // Check for completion events
139
- if (
140
- eventType === EventType.OPERATION_COMPLETED ||
141
- eventType === EventType.OPERATION_ERROR ||
142
- eventType === EventType.OPERATION_CANCELLED
143
- ) {
144
- this.close()
145
- }
146
- } catch (error) {
147
- this.emit('parse_error', { error, rawData: event.data })
148
- }
149
- }
150
-
151
- private async handleError(error: any, operationId: string, fromSequence: number): Promise<void> {
152
- if (this.closed) return
153
-
154
- if (this.reconnectAttempts < this.config.maxRetries!) {
155
- this.reconnectAttempts++
156
- const delay = this.config.retryDelay! * Math.pow(2, this.reconnectAttempts - 1)
157
-
158
- this.emit('reconnecting', {
159
- attempt: this.reconnectAttempts,
160
- delay,
161
- lastEventId: this.lastEventId,
162
- })
163
-
164
- setTimeout(() => {
165
- const resumeFrom = this.lastEventId ? parseInt(this.lastEventId) + 1 : fromSequence
166
- this.connect(operationId, resumeFrom).catch(() => {
167
- // Error handled in connect
168
- })
169
- }, delay)
170
- } else {
171
- this.emit('max_retries_exceeded', error)
172
- this.close()
173
- }
174
- }
175
-
176
- on(event: string, listener: (data: any) => void): void {
177
- if (!this.listeners.has(event)) {
178
- this.listeners.set(event, new Set())
179
- }
180
- this.listeners.get(event)!.add(listener)
181
- }
182
-
183
- off(event: string, listener: (data: any) => void): void {
184
- const listeners = this.listeners.get(event)
185
- if (listeners) {
186
- listeners.delete(listener)
187
- }
188
- }
189
-
190
- private emit(event: string, data: any): void {
191
- const listeners = this.listeners.get(event)
192
- if (listeners) {
193
- listeners.forEach((listener) => listener(data))
194
- }
195
- }
196
-
197
- close(): void {
198
- this.closed = true
199
- if (this.eventSource) {
200
- this.eventSource.close()
201
- this.eventSource = undefined
202
- }
203
- this.emit('closed', null)
204
- this.listeners.clear()
205
- }
206
-
207
- isConnected(): boolean {
208
- return this.eventSource !== undefined && this.eventSource.readyState === EventSource.OPEN
209
- }
210
- }
@@ -1,57 +0,0 @@
1
- /**
2
- * Configuration for SDK extensions
3
- * Provides centralized configuration for CORS, credentials, and other settings
4
- */
5
- export interface SDKExtensionsConfig {
6
- baseUrl?: string;
7
- credentials?: 'include' | 'same-origin' | 'omit';
8
- headers?: Record<string, string>;
9
- token?: string;
10
- timeout?: number;
11
- maxRetries?: number;
12
- retryDelay?: number;
13
- }
14
- /**
15
- * Set global configuration for SDK extensions
16
- * @param config Partial configuration to merge with defaults
17
- */
18
- export declare function setSDKExtensionsConfig(config: Partial<SDKExtensionsConfig>): void;
19
- /**
20
- * Get current SDK extensions configuration
21
- * @returns Current configuration
22
- */
23
- export declare function getSDKExtensionsConfig(): SDKExtensionsConfig;
24
- /**
25
- * Reset configuration to defaults
26
- */
27
- export declare function resetSDKExtensionsConfig(): void;
28
- /**
29
- * Extract JWT token from Authorization header
30
- * @param authHeader Authorization header value
31
- * @returns JWT token or undefined
32
- */
33
- export declare function extractJWTFromHeader(authHeader?: string | string[]): string | undefined;
34
- /**
35
- * Validate JWT token format (basic validation)
36
- * @param token JWT token to validate
37
- * @returns true if token appears valid
38
- */
39
- export declare function isValidJWT(token: string | undefined): boolean;
40
- /**
41
- * Extract JWT token from SDK client configuration
42
- * Centralizes the logic for extracting tokens from the client
43
- * @returns JWT token or undefined
44
- */
45
- export declare function extractTokenFromSDKClient(): string | undefined;
46
- /**
47
- * Configure SDK extensions for JWT authentication
48
- * @param token JWT token
49
- * @param config Additional configuration options
50
- */
51
- export declare function configureWithJWT(token: string, config?: Partial<SDKExtensionsConfig>): void;
52
- /**
53
- * Get configuration for a specific environment
54
- * @param env Environment name (production, staging, development)
55
- * @returns Environment-specific configuration
56
- */
57
- export declare function getEnvironmentConfig(env?: 'production' | 'staging' | 'development'): SDKExtensionsConfig;