@@ -7,21 +7,65 @@ open System.Text.Json.Serialization
77open FSharp.Data .GraphQL
88open FSharp.Data .GraphQL .Shared
99
10+ /// <summary >
11+ /// Represents an invalid WebSocket protocol message.
12+ /// </summary >
13+ /// <param name =" explanation " >The validation failure explanation.</param >
1014type InvalidWebsocketMessageException ( explanation : string ) =
1115 inherit System.Exception ( explanation)
1216
17+ /// <summary >
18+ /// Identifies a GraphQL WebSocket subscription.
19+ /// </summary >
1320type SubscriptionId = string
21+
22+ /// <summary >
23+ /// Represents a disposable handle for an active subscription.
24+ /// </summary >
1425type SubscriptionUnsubscriber = IDisposable
26+
27+ /// <summary >
28+ /// Represents a callback invoked when a subscription is removed.
29+ /// </summary >
1530type OnUnsubscribeAction = SubscriptionId -> unit
31+
32+ /// <summary >
33+ /// Stores active subscriptions keyed by their identifier.
34+ /// </summary >
1635type SubscriptionsDict = IDictionary< SubscriptionId, SubscriptionUnsubscriber * OnUnsubscribeAction>
1736
18- type RawMessage = { Id : string voption ; Type : string ; Payload : JsonDocument voption }
37+ /// <summary >
38+ /// Represents a raw WebSocket message before it is mapped to protocol-specific client messages.
39+ /// </summary >
40+ type RawMessage = {
41+ /// <summary >
42+ /// Gets the message id, when the message is operation-scoped.
43+ /// </summary >
44+ Id : string voption
45+ /// <summary >
46+ /// Gets the protocol message type.
47+ /// </summary >
48+ Type : string
49+ /// <summary >
50+ /// Gets the raw JSON payload.
51+ /// </summary >
52+ Payload : JsonDocument voption
53+ }
1954
2055/// <summary >
2156/// Announces a deferred or streamed field for the first time, identifying it by a short id used in every
2257/// subsequent <see cref =" IncrementalResult " /> or <see cref =" CompletedResult " /> for the same field.
2358/// </summary >
24- type PendingResult = { Id : string ; Path : FieldPath }
59+ type PendingResult = {
60+ /// <summary >
61+ /// Gets the short id assigned to the announced field.
62+ /// </summary >
63+ Id : string
64+ /// <summary >
65+ /// Gets the response path of the announced field.
66+ /// </summary >
67+ Path : FieldPath
68+ }
2569
2670/// <summary >
2771/// One incremental delivery of a deferred or streamed field, identified by the id from its
@@ -32,9 +76,21 @@ type PendingResult = { Id : string; Path : FieldPath }
3276/// <c >@stream </c > field's items, in list order.
3377/// </remarks >
3478type IncrementalResult = {
79+ /// <summary >
80+ /// Gets the id of the deferred or streamed field this payload belongs to.
81+ /// </summary >
3582 Id : string
83+ /// <summary >
84+ /// Gets the deferred field data, when the payload carries deferred data.
85+ /// </summary >
3686 Data : objnull Skippable
87+ /// <summary >
88+ /// Gets the streamed items, when the payload carries streamed data.
89+ /// </summary >
3790 Items : objnull [] Skippable
91+ /// <summary >
92+ /// Gets the execution errors associated with the payload.
93+ /// </summary >
3894 Errors : GQLProblemDetails list Skippable
3995}
4096
@@ -43,7 +99,16 @@ type IncrementalResult = {
4399/// delivered everything it is going to.
44100/// </summary >
45101[<Struct>]
46- type CompletedResult = { Id : string ; Errors : GQLProblemDetails list Skippable }
102+ type CompletedResult = {
103+ /// <summary >
104+ /// Gets the id of the deferred or streamed field that completed.
105+ /// </summary >
106+ Id : string
107+ /// <summary >
108+ /// Gets any completion errors associated with the field.
109+ /// </summary >
110+ Errors : GQLProblemDetails list Skippable
111+ }
47112
48113/// <summary >
49114/// Payload of a <c >next</c > message of the <c >graphql-transport-ws</c > protocol.
@@ -55,22 +120,42 @@ type CompletedResult = { Id : string; Errors : GQLProblemDetails list Skippable
55120/// Client's <c >GraphQL17Alpha9Handler</c >.
56121/// </remarks >
57122type SubscriptionExecutionResult = {
58- /// Result data: an object for a complete or initial payload. Always <see cref =" Skip " /> for a subsequent
59- /// payload, whose deltas are carried by <see cref =" Incremental " /> and <see cref =" Completed " /> instead.
123+ /// <summary >
124+ /// Gets the result data.
125+ /// </summary >
126+ /// <remarks >
127+ /// This is an object for a complete or initial payload. It is always <see cref =" Skip " /> for a subsequent
128+ /// payload, whose deltas are carried by <see cref =" Incremental " /> and <see cref =" Completed " /> instead.
129+ /// </remarks >
60130 Data : obj Skippable
61- /// Errors raised while producing the payload. Always <see cref =" Skip " /> for a subsequent payload.
131+ /// <summary >
132+ /// Gets the errors raised while producing the payload.
133+ /// </summary >
134+ /// <remarks >
135+ /// This is always <see cref =" Skip " /> for a subsequent payload.
136+ /// </remarks >
62137 Errors : GQLProblemDetails list Skippable
63- /// Fields newly announced by this payload.
138+ /// <summary >
139+ /// Gets the fields newly announced by this payload.
140+ /// </summary >
64141 Pending : PendingResult list Skippable
65- /// Deltas of already-announced fields delivered by this payload.
142+ /// <summary >
143+ /// Gets the deltas of already-announced fields delivered by this payload.
144+ /// </summary >
66145 Incremental : IncrementalResult list Skippable
67- /// Fields that finished delivering as of this payload.
146+ /// <summary >
147+ /// Gets the fields that finished delivering as of this payload.
148+ /// </summary >
68149 Completed : CompletedResult list Skippable
69- /// Tells whether more incremental payloads follow.
150+ /// <summary >
151+ /// Gets a value indicating whether more incremental payloads follow.
152+ /// </summary >
70153 HasNext : bool Skippable
71154} with
72155
156+ /// <summary >
73157 /// Creates a payload of a complete execution result.
158+ /// </summary >
74159 static member Create ( data : Output | null , errors : GQLProblemDetails list ) = {
75160 Data = Include ( box data)
76161 Errors = Include errors
@@ -80,7 +165,9 @@ type SubscriptionExecutionResult = {
80165 HasNext = Skip
81166 }
82167
168+ /// <summary >
83169 /// Creates a payload that carries only errors.
170+ /// </summary >
84171 static member CreateErrors ( errors : GQLProblemDetails list ) = {
85172 Data = Include null
86173 Errors = Include errors
@@ -90,7 +177,9 @@ type SubscriptionExecutionResult = {
90177 HasNext = Skip
91178 }
92179
180+ /// <summary >
93181 /// Creates the initial payload of an incremental delivery, which is always followed by subsequent payloads.
182+ /// </summary >
94183 static member CreateInitial ( data : Output | null , errors : GQLProblemDetails list , pending : PendingResult list ) = {
95184 Data = Include ( box data)
96185 Errors = Include errors
@@ -100,8 +189,13 @@ type SubscriptionExecutionResult = {
100189 HasNext = Include true
101190 }
102191
103- /// Creates a subsequent payload of an incremental delivery, carrying the fields it newly announces, the
104- /// deltas it delivers for already-announced fields, and the fields it completes.
192+ /// <summary >
193+ /// Creates a subsequent payload of an incremental delivery.
194+ /// </summary >
195+ /// <remarks >
196+ /// It carries the fields it newly announces, the deltas it delivers for already-announced fields, and the
197+ /// fields it completes.
198+ /// </remarks >
105199 static member CreateSubsequent
106200 ( pending : PendingResult list , incremental : IncrementalResult list , completed : CompletedResult list , hasNext : bool )
107201 = {
@@ -113,34 +207,130 @@ type SubscriptionExecutionResult = {
113207 HasNext = Include hasNext
114208 }
115209
210+ /// <summary >
211+ /// Represents the raw payload of a server WebSocket message.
212+ /// </summary >
116213type ServerRawPayload =
214+ /// <summary >
215+ /// Contains a GraphQL execution result payload.
216+ /// </summary >
117217 | ExecutionResult of SubscriptionExecutionResult
218+ /// <summary >
219+ /// Contains one or more GraphQL error payloads.
220+ /// </summary >
118221 | ErrorMessages of GQLProblemDetails list
222+ /// <summary >
223+ /// Contains a custom JSON payload.
224+ /// </summary >
119225 | CustomResponse of JsonDocument
120226
121- type RawServerMessage = { Id : string voption ; Type : string ; Payload : ServerRawPayload voption }
227+ /// <summary >
228+ /// Represents a raw server WebSocket message.
229+ /// </summary >
230+ type RawServerMessage = {
231+ /// <summary >
232+ /// Gets the message id, when the message is operation-scoped.
233+ /// </summary >
234+ Id : string voption
235+ /// <summary >
236+ /// Gets the protocol message type.
237+ /// </summary >
238+ Type : string
239+ /// <summary >
240+ /// Gets the raw server payload.
241+ /// </summary >
242+ Payload : ServerRawPayload voption
243+ }
122244
245+ /// <summary >
246+ /// Represents a parsed client WebSocket protocol message.
247+ /// </summary >
123248type ClientMessage =
249+ /// <summary >
250+ /// Initializes a protocol connection.
251+ /// </summary >
124252 | ConnectionInit of payload : JsonDocument voption
253+ /// <summary >
254+ /// Sends a client ping frame.
255+ /// </summary >
125256 | ClientPing of payload : JsonDocument voption
257+ /// <summary >
258+ /// Sends a client pong frame.
259+ /// </summary >
126260 | ClientPong of payload : JsonDocument voption
261+ /// <summary >
262+ /// Starts a GraphQL subscription or operation.
263+ /// </summary >
127264 | Subscribe of id : string * query : GQLRequestContent
265+ /// <summary >
266+ /// Completes a client-side operation.
267+ /// </summary >
128268 | ClientComplete of id : string
129269
130- type ClientMessageProtocolFailure = InvalidMessage of code : int * explanation : string
270+ /// <summary >
271+ /// Represents a protocol-level validation failure for an incoming client message.
272+ /// </summary >
273+ type ClientMessageProtocolFailure =
274+ /// <summary >
275+ /// Indicates that the client message failed protocol validation.
276+ /// </summary >
277+ | InvalidMessage of code : int * explanation : string
131278
279+ /// <summary >
280+ /// Represents a server WebSocket protocol message.
281+ /// </summary >
132282type ServerMessage =
283+ /// <summary >
284+ /// Acknowledges a successful connection initialization.
285+ /// </summary >
133286 | ConnectionAck
287+ /// <summary >
288+ /// Sends a server ping frame.
289+ /// </summary >
134290 | ServerPing
291+ /// <summary >
292+ /// Sends a server pong frame.
293+ /// </summary >
135294 | ServerPong of JsonDocument voption
295+ /// <summary >
296+ /// Sends a GraphQL execution payload.
297+ /// </summary >
136298 | Next of id : string * payload : SubscriptionExecutionResult
299+ /// <summary >
300+ /// Sends protocol errors for an operation.
301+ /// </summary >
137302 | Error of id : string * err : GQLProblemDetails list
303+ /// <summary >
304+ /// Marks an operation as complete.
305+ /// </summary >
138306 | Complete of id : string
139307
308+ /// <summary >
309+ /// Defines application-specific GraphQL WebSocket close codes.
310+ /// </summary >
140311module CustomWebSocketStatus =
141312
313+ /// <summary >
314+ /// The client sent an invalid message.
315+ /// </summary >
142316 let InvalidMessage = 4400
317+
318+ /// <summary >
319+ /// The client is not authorized.
320+ /// </summary >
143321 let Unauthorized = 4401
322+
323+ /// <summary >
324+ /// The client did not initialize the connection in time.
325+ /// </summary >
144326 let ConnectionTimeout = 4408
327+
328+ /// <summary >
329+ /// The requested subscription identifier is already in use.
330+ /// </summary >
145331 let SubscriberAlreadyExists = 4409
332+
333+ /// <summary >
334+ /// The client sent too many initialization requests.
335+ /// </summary >
146336 let TooManyInitializationRequests = 4429
0 commit comments