@@ -124,6 +124,39 @@ export const watchWorkspace = (workspaceId: string): EventSource => {
124
124
) ;
125
125
} ;
126
126
127
+ type WatchInboxNotificationsParams = {
128
+ read_status ?: "read" | "unread" | "all" ;
129
+ } ;
130
+
131
+ export const watchInboxNotifications = (
132
+ onNewNotification : ( res : TypesGen . GetInboxNotificationResponse ) => void ,
133
+ params ?: WatchInboxNotificationsParams ,
134
+ ) => {
135
+ const searchParams = new URLSearchParams ( params ) ;
136
+ const socket = createWebSocket (
137
+ "/api/v2/notifications/inbox/watch" ,
138
+ searchParams ,
139
+ ) ;
140
+
141
+ socket . addEventListener ( "message" , ( event ) => {
142
+ try {
143
+ const res = JSON . parse (
144
+ event . data ,
145
+ ) as TypesGen . GetInboxNotificationResponse ;
146
+ onNewNotification ( res ) ;
147
+ } catch ( error ) {
148
+ console . warn ( "Error parsing inbox notification: " , error ) ;
149
+ }
150
+ } ) ;
151
+
152
+ socket . addEventListener ( "error" , ( event ) => {
153
+ console . warn ( "Watch inbox notifications error: " , event ) ;
154
+ socket . close ( ) ;
155
+ } ) ;
156
+
157
+ return socket ;
158
+ } ;
159
+
127
160
export const getURLWithSearchParams = (
128
161
basePath : string ,
129
162
options ?: SearchParamOptions ,
@@ -184,15 +217,11 @@ export const watchBuildLogsByTemplateVersionId = (
184
217
searchParams . append ( "after" , after . toString ( ) ) ;
185
218
}
186
219
187
- const proto = location . protocol === "https:" ? "wss:" : "ws:" ;
188
- const socket = new WebSocket (
189
- `${ proto } //${
190
- location . host
191
- } /api/v2/templateversions/${ versionId } /logs?${ searchParams . toString ( ) } `,
220
+ const socket = createWebSocket (
221
+ `/api/v2/templateversions/${ versionId } /logs` ,
222
+ searchParams ,
192
223
) ;
193
224
194
- socket . binaryType = "blob" ;
195
-
196
225
socket . addEventListener ( "message" , ( event ) =>
197
226
onMessage ( JSON . parse ( event . data ) as TypesGen . ProvisionerJobLog ) ,
198
227
) ;
@@ -214,21 +243,21 @@ export const watchWorkspaceAgentLogs = (
214
243
agentId : string ,
215
244
{ after, onMessage, onDone, onError } : WatchWorkspaceAgentLogsOptions ,
216
245
) => {
217
- // WebSocket compression in Safari (confirmed in 16.5) is broken when
218
- // the server sends large messages. The following error is seen:
219
- //
220
- // WebSocket connection to 'wss://.../logs?follow&after=0' failed: The operation couldn’t be completed. Protocol error
221
- //
222
- const noCompression =
223
- userAgentParser ( navigator . userAgent ) . browser . name === "Safari"
224
- ? "&no_compression"
225
- : "" ;
246
+ const searchParams = new URLSearchParams ( { after : after . toString ( ) } ) ;
226
247
227
- const proto = location . protocol === "https:" ? "wss:" : "ws:" ;
228
- const socket = new WebSocket (
229
- `${ proto } //${ location . host } /api/v2/workspaceagents/${ agentId } /logs?follow&after=${ after } ${ noCompression } ` ,
248
+ /**
249
+ * WebSocket compression in Safari (confirmed in 16.5) is broken when
250
+ * the server sends large messages. The following error is seen:
251
+ * WebSocket connection to 'wss://...' failed: The operation couldn’t be completed.
252
+ */
253
+ if ( userAgentParser ( navigator . userAgent ) . browser . name === "Safari" ) {
254
+ searchParams . set ( "no_compression" , "" ) ;
255
+ }
256
+
257
+ const socket = createWebSocket (
258
+ `/api/v2/workspaceagents/${ agentId } /logs` ,
259
+ searchParams ,
230
260
) ;
231
- socket . binaryType = "blob" ;
232
261
233
262
socket . addEventListener ( "message" , ( event ) => {
234
263
const logs = JSON . parse ( event . data ) as TypesGen . WorkspaceAgentLog [ ] ;
@@ -267,13 +296,11 @@ export const watchBuildLogsByBuildId = (
267
296
if ( after !== undefined ) {
268
297
searchParams . append ( "after" , after . toString ( ) ) ;
269
298
}
270
- const proto = location . protocol === "https:" ? "wss:" : "ws:" ;
271
- const socket = new WebSocket (
272
- `${ proto } //${
273
- location . host
274
- } /api/v2/workspacebuilds/${ buildId } /logs?${ searchParams . toString ( ) } `,
299
+
300
+ const socket = createWebSocket (
301
+ `/api/v2/workspacebuilds/${ buildId } /logs` ,
302
+ searchParams ,
275
303
) ;
276
- socket . binaryType = "blob" ;
277
304
278
305
socket . addEventListener ( "message" , ( event ) =>
279
306
onMessage ( JSON . parse ( event . data ) as TypesGen . ProvisionerJobLog ) ,
@@ -2406,6 +2433,25 @@ class ApiMethods {
2406
2433
) ;
2407
2434
return res . data ;
2408
2435
} ;
2436
+
2437
+ getInboxNotifications = async ( ) => {
2438
+ const res = await this . axios . get < TypesGen . ListInboxNotificationsResponse > (
2439
+ "/api/v2/notifications/inbox" ,
2440
+ ) ;
2441
+ return res . data ;
2442
+ } ;
2443
+
2444
+ updateInboxNotificationReadStatus = async (
2445
+ notificationId : string ,
2446
+ req : TypesGen . UpdateInboxNotificationReadStatusRequest ,
2447
+ ) => {
2448
+ const res =
2449
+ await this . axios . put < TypesGen . UpdateInboxNotificationReadStatusResponse > (
2450
+ `/api/v2/notifications/inbox/${ notificationId } /read-status` ,
2451
+ req ,
2452
+ ) ;
2453
+ return res . data ;
2454
+ } ;
2409
2455
}
2410
2456
2411
2457
// This is a hard coded CSRF token/cookie pair for local development. In prod,
@@ -2457,6 +2503,21 @@ function getConfiguredAxiosInstance(): AxiosInstance {
2457
2503
return instance ;
2458
2504
}
2459
2505
2506
+ /**
2507
+ * Utility function to help create a WebSocket connection with Coder's API.
2508
+ */
2509
+ function createWebSocket (
2510
+ path : string ,
2511
+ params : URLSearchParams = new URLSearchParams ( ) ,
2512
+ ) {
2513
+ const protocol = location . protocol === "https:" ? "wss:" : "ws:" ;
2514
+ const socket = new WebSocket (
2515
+ `${ protocol } //${ location . host } ${ path } ?${ params . toString ( ) } ` ,
2516
+ ) ;
2517
+ socket . binaryType = "blob" ;
2518
+ return socket ;
2519
+ }
2520
+
2460
2521
// Other non-API methods defined here to make it a little easier to find them.
2461
2522
interface ClientApi extends ApiMethods {
2462
2523
getCsrfToken : ( ) => string ;
0 commit comments