@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
@@ -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;