@stack-spot/portal-network 0.184.0-beta.1 → 0.184.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 (151) hide show
  1. package/CHANGELOG.md +2412 -2431
  2. package/dist/api/account.js +1 -1
  3. package/dist/api/agent-tools.js +1 -1
  4. package/dist/api/agent.js +1 -1
  5. package/dist/api/ai.js +1 -1
  6. package/dist/api/apiManagement.js +1 -1
  7. package/dist/api/apiRuntime.js +1 -1
  8. package/dist/api/cloudAccount.js +1 -1
  9. package/dist/api/cloudPlatform.js +1 -1
  10. package/dist/api/cloudPlatformHorizon.js +1 -1
  11. package/dist/api/cloudRuntimes.js +1 -1
  12. package/dist/api/cloudServices.js +1 -1
  13. package/dist/api/codeShift.d.ts +4 -76
  14. package/dist/api/codeShift.d.ts.map +1 -1
  15. package/dist/api/codeShift.js +1 -14
  16. package/dist/api/codeShift.js.map +1 -1
  17. package/dist/api/content.js +1 -1
  18. package/dist/api/dataIntegration.js +1 -1
  19. package/dist/api/discover.js +1 -1
  20. package/dist/api/genAiInference.js +1 -1
  21. package/dist/api/insights.js +1 -1
  22. package/dist/api/notification.js +1 -1
  23. package/dist/api/secrets.js +1 -1
  24. package/dist/api/serviceCatalog.js +1 -1
  25. package/dist/api/workspace-ai.js +1 -1
  26. package/dist/api/workspace.js +1 -1
  27. package/dist/api/workspaceManager.d.ts +16 -10
  28. package/dist/api/workspaceManager.d.ts.map +1 -1
  29. package/dist/api/workspaceManager.js +11 -1
  30. package/dist/api/workspaceManager.js.map +1 -1
  31. package/dist/api/workspaceSearchEngine.js +1 -1
  32. package/dist/client/ai.d.ts.map +1 -1
  33. package/dist/client/ai.js +14 -84
  34. package/dist/client/ai.js.map +1 -1
  35. package/dist/client/code-shift.d.ts +0 -30
  36. package/dist/client/code-shift.d.ts.map +1 -1
  37. package/dist/client/code-shift.js +1 -37
  38. package/dist/client/code-shift.js.map +1 -1
  39. package/dist/client/types.d.ts +6 -26
  40. package/dist/client/types.d.ts.map +1 -1
  41. package/dist/client/workspace-manager.d.ts +6 -0
  42. package/dist/client/workspace-manager.d.ts.map +1 -1
  43. package/dist/client/workspace-manager.js +10 -1
  44. package/dist/client/workspace-manager.js.map +1 -1
  45. package/package.json +1 -1
  46. package/readme.md +1 -1
  47. package/scripts/generate-apis.ts +134 -134
  48. package/src/api/account.ts +8367 -8368
  49. package/src/api/agent-tools.ts +2169 -2172
  50. package/src/api/agent.ts +1083 -1085
  51. package/src/api/ai.ts +3388 -3388
  52. package/src/api/apiManagement.ts +570 -570
  53. package/src/api/apiRuntime.ts +2103 -2103
  54. package/src/api/cloudAccount.ts +1239 -1239
  55. package/src/api/cloudPlatform.ts +927 -927
  56. package/src/api/cloudPlatformHorizon.ts +2655 -2655
  57. package/src/api/cloudRuntimes.ts +2043 -2043
  58. package/src/api/cloudServices.ts +1445 -1445
  59. package/src/api/codeShift.ts +3481 -3580
  60. package/src/api/content.ts +9785 -9785
  61. package/src/api/dataIntegration.ts +1657 -1657
  62. package/src/api/discover.ts +435 -435
  63. package/src/api/eventBus.ts +171 -171
  64. package/src/api/genAiInference.ts +603 -603
  65. package/src/api/insights.ts +310 -310
  66. package/src/api/notification.ts +334 -336
  67. package/src/api/secrets.ts +342 -342
  68. package/src/api/serviceCatalog.ts +2908 -2908
  69. package/src/api/workflows.ts +1669 -1669
  70. package/src/api/workspace-ai.ts +677 -677
  71. package/src/api/workspace.ts +5889 -5889
  72. package/src/api/workspaceManager.ts +2951 -2936
  73. package/src/api/workspaceSearchEngine.ts +153 -153
  74. package/src/api-addresses.ts +120 -120
  75. package/src/apis-itau.json +225 -225
  76. package/src/apis.json +225 -225
  77. package/src/client/account.ts +902 -902
  78. package/src/client/agent-tools.ts +210 -210
  79. package/src/client/agent.ts +81 -81
  80. package/src/client/ai.ts +395 -469
  81. package/src/client/api-management.ts +40 -40
  82. package/src/client/cloud-account.ts +70 -70
  83. package/src/client/cloud-platform-horizon.ts +113 -113
  84. package/src/client/cloud-platform.ts +163 -163
  85. package/src/client/cloud-runtimes.ts +129 -129
  86. package/src/client/cloud-services.ts +94 -94
  87. package/src/client/code-shift.ts +349 -371
  88. package/src/client/content.ts +538 -538
  89. package/src/client/data-integration.ts +191 -191
  90. package/src/client/discover.ts +89 -89
  91. package/src/client/event-bus.ts +84 -84
  92. package/src/client/gen-ai-inference.ts +65 -65
  93. package/src/client/insights.ts +28 -28
  94. package/src/client/notification.ts +32 -32
  95. package/src/client/runtime-manager.ts +76 -76
  96. package/src/client/secrets.ts +60 -60
  97. package/src/client/types.ts +377 -398
  98. package/src/client/workflow.ts +83 -83
  99. package/src/client/workspace-ai.ts +191 -191
  100. package/src/client/workspace-manager.ts +564 -560
  101. package/src/client/workspace-search.ts +39 -39
  102. package/src/client/workspace.ts +480 -480
  103. package/src/error/DefaultAPIError.ts +151 -151
  104. package/src/error/FileUploadError.ts +18 -18
  105. package/src/error/IgnoredErrorCodes.ts +3 -3
  106. package/src/error/StackspotAPIError.ts +101 -101
  107. package/src/error/StreamCanceledError.ts +10 -10
  108. package/src/error/StreamError.ts +7 -7
  109. package/src/error/StreamJsonError.ts +10 -10
  110. package/src/error/dictionary/account.ts +58 -58
  111. package/src/error/dictionary/action-details.ts +20 -20
  112. package/src/error/dictionary/action.ts +211 -211
  113. package/src/error/dictionary/agent-tools.ts +75 -75
  114. package/src/error/dictionary/ai-inference.ts +28 -28
  115. package/src/error/dictionary/base.ts +22 -22
  116. package/src/error/dictionary/cloud-platform.ts +82 -82
  117. package/src/error/dictionary/cnt-fields.ts +14 -14
  118. package/src/error/dictionary/cnt.ts +103 -103
  119. package/src/error/dictionary/code-shift.ts +12 -12
  120. package/src/error/dictionary/rte.ts +24 -24
  121. package/src/error/dictionary/rtm.ts +10 -10
  122. package/src/error/dictionary/secrets.ts +14 -14
  123. package/src/error/dictionary/workspace-ai.ts +10 -10
  124. package/src/error/dictionary/workspace-details.ts +15 -15
  125. package/src/error/dictionary/workspace-fields.ts +10 -10
  126. package/src/error/dictionary/workspace.ts +209 -209
  127. package/src/error/types.ts +21 -21
  128. package/src/index.ts +43 -43
  129. package/src/network/AutoInfiniteQuery.ts +115 -115
  130. package/src/network/AutoMutation.ts +27 -27
  131. package/src/network/AutoOperation.ts +73 -73
  132. package/src/network/AutoQuery.ts +75 -75
  133. package/src/network/ManualInfiniteQuery.ts +95 -95
  134. package/src/network/ManualMutation.ts +40 -40
  135. package/src/network/ManualOperation.ts +52 -52
  136. package/src/network/ManualQuery.ts +82 -82
  137. package/src/network/NetworkClient.ts +167 -167
  138. package/src/network/ReactQueryNetworkClient.ts +312 -312
  139. package/src/network/react-query-client.ts +14 -14
  140. package/src/network/types.ts +294 -294
  141. package/src/types.ts +1 -1
  142. package/src/utils/StreamedArray.tsx +146 -146
  143. package/src/utils/StreamedJson.tsx +166 -166
  144. package/src/utils/remove-authorization-param.ts +6 -6
  145. package/src/utils/string.ts +19 -19
  146. package/src/utils/use-extended-list.ts +80 -80
  147. package/src/utils/use-streamed-array.ts +17 -17
  148. package/tsconfig.build.json +4 -4
  149. package/tsconfig.json +10 -10
  150. package/logs/simple-failure/01JBER7AWKACEC3Y1NF7M6PHFF/job_id_1.log +0 -3
  151. package/logs/simple-suspend/01JBEMQG94ADPT99MSZ7EJKGXZ/job_id_1.log +0 -5
@@ -1,146 +1,146 @@
1
- import { CompletablePromise } from '@stack-spot/opa'
2
- import { StreamCanceledError } from '../error/StreamCanceledError'
3
- import { StreamError } from '../error/StreamError'
4
- import { StreamJsonError } from '../error/StreamJsonError'
5
- import { FetchEventStream } from '../network/types'
6
- import { StreamingStatus } from '../types'
7
-
8
- type OnChangeListener<T> = (value: T[]) => void
9
-
10
- interface ConstructorParams {
11
- /**
12
- * The promises that result in the EventStreams to build the final array.
13
- */
14
- eventsPromises: Promise<FetchEventStream>[],
15
- /**
16
- * A controller to abort the streaming.
17
- */
18
- abortController?: AbortController,
19
- /**
20
- * A minimum number of milliseconds to wait before calling onChange listeners.
21
- * @default 50
22
- */
23
- minChangeIntervalMS?: number,
24
- /***
25
- * Aborts this stream when the signal is aborted.
26
- */
27
- signal?: AbortSignal,
28
- }
29
-
30
- /**
31
- * An array represented by a stream where each event contains an item of the array as a JSON string. This can be watched as the stream runs.
32
- */
33
- export class StreamedArray<T> {
34
- private onChangeListeners: OnChangeListener<T>[] = []
35
- private error: StreamError | undefined
36
- private data: T[] = []
37
- private fullPromise = new CompletablePromise<T[]>()
38
- private abortController: AbortController | undefined
39
-
40
- /**
41
- * @param response the fetch response.
42
- * @param minChangeIntervalMS a stream can be too fast. This sets a minimum interval between running the listeners. The default is 50ms.
43
- */
44
- constructor({ eventsPromises, abortController, minChangeIntervalMS = 50, signal }: ConstructorParams) {
45
- this.abortController = abortController ?? new AbortController()
46
- eventsPromises.forEach(eventsPromise => this.run(eventsPromise, minChangeIntervalMS))
47
- if (signal) {
48
- signal.addEventListener('abort', () => this.cancel())
49
- }
50
- }
51
-
52
- private async run(eventsPromise: Promise<FetchEventStream>, minChangeIntervalMS: number) {
53
- let lastChangeCall = 0
54
- try {
55
- const events = await eventsPromise
56
- let flushed = true
57
- for await (const event of events) {
58
- if (this.error) return
59
- if (event.data) {
60
- this.data.push(JSON.parse(event.data))
61
- if (new Date().getTime() - lastChangeCall >= minChangeIntervalMS) {
62
- this.onChangeListeners.forEach(l => l(this.data))
63
- lastChangeCall = new Date().getTime()
64
- flushed = true
65
- } else {
66
- flushed = false
67
- }
68
- }
69
- }
70
- if (!flushed) this.onChangeListeners.forEach(l => l(this.data))
71
- } catch (error: any) {
72
- if (error instanceof DOMException && error.name === 'AbortError') this.fail(new StreamCanceledError())
73
- if (error instanceof SyntaxError) this.fail(new StreamJsonError())
74
- else if (error instanceof StreamError) this.fail(error)
75
- else this.fail(new StreamError(error?.message || `${error}`))
76
- }
77
- if (!this.error) this.complete()
78
- }
79
-
80
- private clear() {
81
- this.onChangeListeners = []
82
- this.abortController = undefined
83
- }
84
-
85
- private fail(error: any) {
86
- this.error = error
87
- this.fullPromise.reject(this.error)
88
- this.clear()
89
- }
90
-
91
- private complete() {
92
- this.fullPromise.resolve(this.data)
93
- this.clear()
94
- }
95
-
96
- /**
97
- * Returns the full value of the array once the stream finishes.
98
- */
99
- getValue(): Promise<T[]> {
100
- return this.fullPromise.promise
101
- }
102
-
103
- /**
104
- * Returns the streamed array with every item streamed until now. This will be the complete array if the stream has finished.
105
- */
106
- getPartialValue(): T[] {
107
- return this.data
108
- }
109
-
110
- /**
111
- * Watches the array as it's streamed. This doesn't wait for the value to be complete.
112
- *
113
- * The listener is called whenever the value changes.
114
- *
115
- * @param listener the function to call with the new value.
116
- * @returns a function that, when called, removes the listener.
117
- */
118
- onChange(listener: (value: T[]) => void) {
119
- if (this.fullPromise.resolved) {
120
- listener(this.data)
121
- return () => {}
122
- }
123
- this.onChangeListeners.push(listener)
124
- return () => {
125
- const index = this.onChangeListeners?.findIndex(l => l === listener)
126
- if (index !== undefined && index >= 0) this.onChangeListeners?.splice(index, 1)
127
- }
128
- }
129
-
130
- getStatus(): StreamingStatus {
131
- if (this.error) return 'error'
132
- if (this.fullPromise.resolved) return 'success'
133
- return 'pending'
134
- }
135
-
136
- getError() {
137
- return this.error
138
- }
139
-
140
- /**
141
- * If this is a stream and it's not yet finished, calling this function cancels the stream.
142
- */
143
- cancel() {
144
- this.abortController?.abort(new StreamCanceledError())
145
- }
146
- }
1
+ import { CompletablePromise } from '@stack-spot/opa'
2
+ import { StreamCanceledError } from '../error/StreamCanceledError'
3
+ import { StreamError } from '../error/StreamError'
4
+ import { StreamJsonError } from '../error/StreamJsonError'
5
+ import { FetchEventStream } from '../network/types'
6
+ import { StreamingStatus } from '../types'
7
+
8
+ type OnChangeListener<T> = (value: T[]) => void
9
+
10
+ interface ConstructorParams {
11
+ /**
12
+ * The promises that result in the EventStreams to build the final array.
13
+ */
14
+ eventsPromises: Promise<FetchEventStream>[],
15
+ /**
16
+ * A controller to abort the streaming.
17
+ */
18
+ abortController?: AbortController,
19
+ /**
20
+ * A minimum number of milliseconds to wait before calling onChange listeners.
21
+ * @default 50
22
+ */
23
+ minChangeIntervalMS?: number,
24
+ /***
25
+ * Aborts this stream when the signal is aborted.
26
+ */
27
+ signal?: AbortSignal,
28
+ }
29
+
30
+ /**
31
+ * An array represented by a stream where each event contains an item of the array as a JSON string. This can be watched as the stream runs.
32
+ */
33
+ export class StreamedArray<T> {
34
+ private onChangeListeners: OnChangeListener<T>[] = []
35
+ private error: StreamError | undefined
36
+ private data: T[] = []
37
+ private fullPromise = new CompletablePromise<T[]>()
38
+ private abortController: AbortController | undefined
39
+
40
+ /**
41
+ * @param response the fetch response.
42
+ * @param minChangeIntervalMS a stream can be too fast. This sets a minimum interval between running the listeners. The default is 50ms.
43
+ */
44
+ constructor({ eventsPromises, abortController, minChangeIntervalMS = 50, signal }: ConstructorParams) {
45
+ this.abortController = abortController ?? new AbortController()
46
+ eventsPromises.forEach(eventsPromise => this.run(eventsPromise, minChangeIntervalMS))
47
+ if (signal) {
48
+ signal.addEventListener('abort', () => this.cancel())
49
+ }
50
+ }
51
+
52
+ private async run(eventsPromise: Promise<FetchEventStream>, minChangeIntervalMS: number) {
53
+ let lastChangeCall = 0
54
+ try {
55
+ const events = await eventsPromise
56
+ let flushed = true
57
+ for await (const event of events) {
58
+ if (this.error) return
59
+ if (event.data) {
60
+ this.data.push(JSON.parse(event.data))
61
+ if (new Date().getTime() - lastChangeCall >= minChangeIntervalMS) {
62
+ this.onChangeListeners.forEach(l => l(this.data))
63
+ lastChangeCall = new Date().getTime()
64
+ flushed = true
65
+ } else {
66
+ flushed = false
67
+ }
68
+ }
69
+ }
70
+ if (!flushed) this.onChangeListeners.forEach(l => l(this.data))
71
+ } catch (error: any) {
72
+ if (error instanceof DOMException && error.name === 'AbortError') this.fail(new StreamCanceledError())
73
+ if (error instanceof SyntaxError) this.fail(new StreamJsonError())
74
+ else if (error instanceof StreamError) this.fail(error)
75
+ else this.fail(new StreamError(error?.message || `${error}`))
76
+ }
77
+ if (!this.error) this.complete()
78
+ }
79
+
80
+ private clear() {
81
+ this.onChangeListeners = []
82
+ this.abortController = undefined
83
+ }
84
+
85
+ private fail(error: any) {
86
+ this.error = error
87
+ this.fullPromise.reject(this.error)
88
+ this.clear()
89
+ }
90
+
91
+ private complete() {
92
+ this.fullPromise.resolve(this.data)
93
+ this.clear()
94
+ }
95
+
96
+ /**
97
+ * Returns the full value of the array once the stream finishes.
98
+ */
99
+ getValue(): Promise<T[]> {
100
+ return this.fullPromise.promise
101
+ }
102
+
103
+ /**
104
+ * Returns the streamed array with every item streamed until now. This will be the complete array if the stream has finished.
105
+ */
106
+ getPartialValue(): T[] {
107
+ return this.data
108
+ }
109
+
110
+ /**
111
+ * Watches the array as it's streamed. This doesn't wait for the value to be complete.
112
+ *
113
+ * The listener is called whenever the value changes.
114
+ *
115
+ * @param listener the function to call with the new value.
116
+ * @returns a function that, when called, removes the listener.
117
+ */
118
+ onChange(listener: (value: T[]) => void) {
119
+ if (this.fullPromise.resolved) {
120
+ listener(this.data)
121
+ return () => {}
122
+ }
123
+ this.onChangeListeners.push(listener)
124
+ return () => {
125
+ const index = this.onChangeListeners?.findIndex(l => l === listener)
126
+ if (index !== undefined && index >= 0) this.onChangeListeners?.splice(index, 1)
127
+ }
128
+ }
129
+
130
+ getStatus(): StreamingStatus {
131
+ if (this.error) return 'error'
132
+ if (this.fullPromise.resolved) return 'success'
133
+ return 'pending'
134
+ }
135
+
136
+ getError() {
137
+ return this.error
138
+ }
139
+
140
+ /**
141
+ * If this is a stream and it's not yet finished, calling this function cancels the stream.
142
+ */
143
+ cancel() {
144
+ this.abortController?.abort(new StreamCanceledError())
145
+ }
146
+ }
@@ -1,166 +1,166 @@
1
- import { CompletablePromise } from '@stack-spot/opa'
2
- import { StreamCanceledError } from '../error/StreamCanceledError'
3
- import { StreamError } from '../error/StreamError'
4
- import { StreamJsonError } from '../error/StreamJsonError'
5
- import { FetchEventStream } from '../network/types'
6
- import { StreamingStatus } from '../types'
7
-
8
- type OnChangeListener<T> = (value: Partial<T>) => void
9
-
10
- interface ConstructorParams<T> {
11
- /**
12
- * The promise that results in the EventStream to build the final json.
13
- */
14
- eventsPromise: Promise<FetchEventStream>,
15
- /**
16
- * A controller to abort the streaming.
17
- */
18
- abortController: AbortController,
19
- /**
20
- * A minimum number of milliseconds to wait before calling onChange listeners.
21
- * @default 50
22
- */
23
- minChangeIntervalMS?: number,
24
- /**
25
- * Optional. If set, this function will be called with every streaming event and must transform the current data object according to the
26
- * message received.
27
- */
28
- transform?: (event: Partial<T>, data: Partial<T>) => void | Promise<void>,
29
- /**
30
- * Optional. Keys to ignore when merging the result with the current event. Ignored keys are always replaced by the newest value instead
31
- * of merged.
32
- */
33
- ignoreKeys?: (keyof T)[],
34
- }
35
-
36
- /**
37
- * An object represented by a JSON stream. This can be watched as the stream runs.
38
- */
39
- export class StreamedJson<T> {
40
- private onChangeListeners: OnChangeListener<T>[] = []
41
- private error: StreamError | undefined
42
- private data: Partial<T> = {}
43
- private fullPromise = new CompletablePromise<T>()
44
- private abortController: AbortController | undefined
45
- private transform?: (event: Partial<T>, data: Partial<T>) => void | Promise<void>
46
- private ignoreKeys?: (keyof T)[]
47
-
48
- /**
49
- * @param response the fetch response.
50
- * @param minChangeIntervalMS a stream can be too fast. This sets a minimum interval between running the listeners. The default is 50ms.
51
- */
52
- constructor({ eventsPromise, abortController, minChangeIntervalMS = 50, transform, ignoreKeys }: ConstructorParams<T>) {
53
- this.abortController = abortController
54
- this.transform = transform
55
- this.ignoreKeys = ignoreKeys
56
- this.run(eventsPromise, minChangeIntervalMS)
57
- }
58
-
59
- private async run(eventsPromise: Promise<FetchEventStream>, minChangeIntervalMS: number) {
60
- let lastChangeCall = 0
61
- try {
62
- const events = await eventsPromise
63
- let flushed = true
64
- for await (const event of events) {
65
- if (this.error) return
66
- if (event.data) {
67
- const json = JSON.parse(event.data)
68
- await this.transform?.(json, this.data)
69
- this.merge(json, this.data)
70
- if (new Date().getTime() - lastChangeCall >= minChangeIntervalMS) {
71
- this.onChangeListeners.forEach(l => l(this.data))
72
- lastChangeCall = new Date().getTime()
73
- flushed = true
74
- } else {
75
- flushed = false
76
- }
77
- }
78
- }
79
- if (!flushed) this.onChangeListeners.forEach(l => l(this.data))
80
- } catch (error: any) {
81
- if (error instanceof DOMException && error.name === 'AbortError') this.fail(new StreamCanceledError())
82
- if (error instanceof SyntaxError) this.fail(new StreamJsonError())
83
- else if (error instanceof StreamError) this.fail(error)
84
- else this.fail(new StreamError(error?.message || `${error}`))
85
- }
86
- if (!this.error) this.complete()
87
- }
88
-
89
- private merge(source: Record<string, any>, target: Record<string, any>) {
90
- Object.keys(source).forEach((k) => {
91
- if (this.ignoreKeys?.includes(k as keyof T) || typeof source[k] !== typeof target[k]) target[k] = source[k]
92
- else if (typeof source[k] === 'string') target[k] += source[k]
93
- else if (Array.isArray(source[k])) target[k].push(...source[k])
94
- else if (typeof source[k] === 'number') parseFloat(target[k] + source[k])
95
- else if (source[k] && typeof source[k] === 'object') this.merge(source[k], target[k])
96
- else if (source[k]) target[k] = source[k]
97
- })
98
- }
99
-
100
- private clear() {
101
- this.onChangeListeners = []
102
- this.abortController = undefined
103
- }
104
-
105
- private fail(error: any) {
106
- this.error = error
107
- this.fullPromise.reject(this.error)
108
- this.clear()
109
- }
110
-
111
- private complete() {
112
- this.fullPromise.resolve(this.data as T)
113
- this.clear()
114
- }
115
-
116
- /**
117
- * Returns the full value of the object once the stream finishes.
118
- */
119
- getValue(): Promise<T> {
120
- return this.fullPromise.promise
121
- }
122
-
123
- /**
124
- * Returns the streamed object with everything already streamed. This will be the complete object if the stream has finished.
125
- */
126
- getPartialValue(): Partial<T> {
127
- return this.data
128
- }
129
-
130
- /**
131
- * Watches the object as it's streamed. This doesn't wait for the value to be complete.
132
- *
133
- * The listener is called whenever the value changes.
134
- *
135
- * @param listener the function to call with the new value.
136
- * @returns a function that, when called, removes the listener.
137
- */
138
- onChange(listener: (value: Partial<T>) => void) {
139
- if (this.fullPromise.resolved) {
140
- listener(this.data)
141
- return () => {}
142
- }
143
- this.onChangeListeners.push(listener)
144
- return () => {
145
- const index = this.onChangeListeners?.findIndex(l => l === listener)
146
- if (index !== undefined && index >= 0) this.onChangeListeners?.splice(index, 1)
147
- }
148
- }
149
-
150
- getStatus(): StreamingStatus {
151
- if (this.error) return 'error'
152
- if (this.fullPromise.resolved) return 'success'
153
- return 'pending'
154
- }
155
-
156
- getError() {
157
- return this.error
158
- }
159
-
160
- /**
161
- * If this is a stream and it's not yet finished, calling this function cancels the stream.
162
- */
163
- cancel() {
164
- this.abortController?.abort(new StreamCanceledError())
165
- }
166
- }
1
+ import { CompletablePromise } from '@stack-spot/opa'
2
+ import { StreamCanceledError } from '../error/StreamCanceledError'
3
+ import { StreamError } from '../error/StreamError'
4
+ import { StreamJsonError } from '../error/StreamJsonError'
5
+ import { FetchEventStream } from '../network/types'
6
+ import { StreamingStatus } from '../types'
7
+
8
+ type OnChangeListener<T> = (value: Partial<T>) => void
9
+
10
+ interface ConstructorParams<T> {
11
+ /**
12
+ * The promise that results in the EventStream to build the final json.
13
+ */
14
+ eventsPromise: Promise<FetchEventStream>,
15
+ /**
16
+ * A controller to abort the streaming.
17
+ */
18
+ abortController: AbortController,
19
+ /**
20
+ * A minimum number of milliseconds to wait before calling onChange listeners.
21
+ * @default 50
22
+ */
23
+ minChangeIntervalMS?: number,
24
+ /**
25
+ * Optional. If set, this function will be called with every streaming event and must transform the current data object according to the
26
+ * message received.
27
+ */
28
+ transform?: (event: Partial<T>, data: Partial<T>) => void | Promise<void>,
29
+ /**
30
+ * Optional. Keys to ignore when merging the result with the current event. Ignored keys are always replaced by the newest value instead
31
+ * of merged.
32
+ */
33
+ ignoreKeys?: (keyof T)[],
34
+ }
35
+
36
+ /**
37
+ * An object represented by a JSON stream. This can be watched as the stream runs.
38
+ */
39
+ export class StreamedJson<T> {
40
+ private onChangeListeners: OnChangeListener<T>[] = []
41
+ private error: StreamError | undefined
42
+ private data: Partial<T> = {}
43
+ private fullPromise = new CompletablePromise<T>()
44
+ private abortController: AbortController | undefined
45
+ private transform?: (event: Partial<T>, data: Partial<T>) => void | Promise<void>
46
+ private ignoreKeys?: (keyof T)[]
47
+
48
+ /**
49
+ * @param response the fetch response.
50
+ * @param minChangeIntervalMS a stream can be too fast. This sets a minimum interval between running the listeners. The default is 50ms.
51
+ */
52
+ constructor({ eventsPromise, abortController, minChangeIntervalMS = 50, transform, ignoreKeys }: ConstructorParams<T>) {
53
+ this.abortController = abortController
54
+ this.transform = transform
55
+ this.ignoreKeys = ignoreKeys
56
+ this.run(eventsPromise, minChangeIntervalMS)
57
+ }
58
+
59
+ private async run(eventsPromise: Promise<FetchEventStream>, minChangeIntervalMS: number) {
60
+ let lastChangeCall = 0
61
+ try {
62
+ const events = await eventsPromise
63
+ let flushed = true
64
+ for await (const event of events) {
65
+ if (this.error) return
66
+ if (event.data) {
67
+ const json = JSON.parse(event.data)
68
+ await this.transform?.(json, this.data)
69
+ this.merge(json, this.data)
70
+ if (new Date().getTime() - lastChangeCall >= minChangeIntervalMS) {
71
+ this.onChangeListeners.forEach(l => l(this.data))
72
+ lastChangeCall = new Date().getTime()
73
+ flushed = true
74
+ } else {
75
+ flushed = false
76
+ }
77
+ }
78
+ }
79
+ if (!flushed) this.onChangeListeners.forEach(l => l(this.data))
80
+ } catch (error: any) {
81
+ if (error instanceof DOMException && error.name === 'AbortError') this.fail(new StreamCanceledError())
82
+ if (error instanceof SyntaxError) this.fail(new StreamJsonError())
83
+ else if (error instanceof StreamError) this.fail(error)
84
+ else this.fail(new StreamError(error?.message || `${error}`))
85
+ }
86
+ if (!this.error) this.complete()
87
+ }
88
+
89
+ private merge(source: Record<string, any>, target: Record<string, any>) {
90
+ Object.keys(source).forEach((k) => {
91
+ if (this.ignoreKeys?.includes(k as keyof T) || typeof source[k] !== typeof target[k]) target[k] = source[k]
92
+ else if (typeof source[k] === 'string') target[k] += source[k]
93
+ else if (Array.isArray(source[k])) target[k].push(...source[k])
94
+ else if (typeof source[k] === 'number') parseFloat(target[k] + source[k])
95
+ else if (source[k] && typeof source[k] === 'object') this.merge(source[k], target[k])
96
+ else if (source[k]) target[k] = source[k]
97
+ })
98
+ }
99
+
100
+ private clear() {
101
+ this.onChangeListeners = []
102
+ this.abortController = undefined
103
+ }
104
+
105
+ private fail(error: any) {
106
+ this.error = error
107
+ this.fullPromise.reject(this.error)
108
+ this.clear()
109
+ }
110
+
111
+ private complete() {
112
+ this.fullPromise.resolve(this.data as T)
113
+ this.clear()
114
+ }
115
+
116
+ /**
117
+ * Returns the full value of the object once the stream finishes.
118
+ */
119
+ getValue(): Promise<T> {
120
+ return this.fullPromise.promise
121
+ }
122
+
123
+ /**
124
+ * Returns the streamed object with everything already streamed. This will be the complete object if the stream has finished.
125
+ */
126
+ getPartialValue(): Partial<T> {
127
+ return this.data
128
+ }
129
+
130
+ /**
131
+ * Watches the object as it's streamed. This doesn't wait for the value to be complete.
132
+ *
133
+ * The listener is called whenever the value changes.
134
+ *
135
+ * @param listener the function to call with the new value.
136
+ * @returns a function that, when called, removes the listener.
137
+ */
138
+ onChange(listener: (value: Partial<T>) => void) {
139
+ if (this.fullPromise.resolved) {
140
+ listener(this.data)
141
+ return () => {}
142
+ }
143
+ this.onChangeListeners.push(listener)
144
+ return () => {
145
+ const index = this.onChangeListeners?.findIndex(l => l === listener)
146
+ if (index !== undefined && index >= 0) this.onChangeListeners?.splice(index, 1)
147
+ }
148
+ }
149
+
150
+ getStatus(): StreamingStatus {
151
+ if (this.error) return 'error'
152
+ if (this.fullPromise.resolved) return 'success'
153
+ return 'pending'
154
+ }
155
+
156
+ getError() {
157
+ return this.error
158
+ }
159
+
160
+ /**
161
+ * If this is a stream and it's not yet finished, calling this function cancels the stream.
162
+ */
163
+ cancel() {
164
+ this.abortController?.abort(new StreamCanceledError())
165
+ }
166
+ }
@@ -1,6 +1,6 @@
1
- import { FixVariables, OazapftsFunction } from '../client/types'
2
-
3
- export function removeAuthorizationParam<T extends OazapftsFunction>(fn: T): FixVariables<T,
4
- { authorization: never, jwtToken: never, authorizationHeader: never }> {
5
- return fn
6
- }
1
+ import { FixVariables, OazapftsFunction } from '../client/types'
2
+
3
+ export function removeAuthorizationParam<T extends OazapftsFunction>(fn: T): FixVariables<T,
4
+ { authorization: never, jwtToken: never, authorizationHeader: never }> {
5
+ return fn
6
+ }