-
-
Notifications
You must be signed in to change notification settings - Fork 23
/
Copy pathcommon.ts
177 lines (159 loc) · 4.49 KB
/
common.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
/**
*
* common
*
*/
import type { GraphQLError } from 'graphql';
import { isObject } from './utils';
/**
* Header key through which the event stream token is transmitted
* when using the client in "single connection mode".
*
* Read more: https://github.com/enisdenjo/graphql-sse/blob/master/PROTOCOL.md#single-connection-mode
*
* @category Common
*/
export const TOKEN_HEADER_KEY = 'x-graphql-event-stream-token' as const;
/**
* URL query parameter key through which the event stream token is transmitted
* when using the client in "single connection mode".
*
* Read more: https://github.com/enisdenjo/graphql-sse/blob/master/PROTOCOL.md#single-connection-mode
*
* @category Common
*/
export const TOKEN_QUERY_KEY = 'token' as const;
/**
* Parameters for GraphQL's request for execution.
*
* Reference: https://github.com/graphql/graphql-over-http/blob/main/spec/GraphQLOverHTTP.md#request
*
* @category Common
*/
export interface RequestParams {
operationName?: string;
query: string;
variables?: Record<string, unknown>;
extensions?: Record<string, unknown>;
}
/**
* Represents a message in an event stream.
*
* Read more: https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format
*
* @category Common
*/
export interface StreamMessage<ForID extends boolean, E extends StreamEvent> {
// id?: string; might be used in future releases for connection recovery
event: E;
data: ForID extends true ? StreamDataForID<E> : StreamData<E>;
// retry?: number; ignored since graphql-sse implements custom retry strategies
}
/** @category Common */
export type StreamEvent = 'next' | 'complete';
/** @category Common */
export function validateStreamEvent(e: unknown): StreamEvent {
e = e as StreamEvent;
if (e !== 'next' && e !== 'complete')
throw new Error(`Invalid stream event "${e}"`);
return e;
}
/** @category Common */
export function print<ForID extends boolean, E extends StreamEvent>(
msg: StreamMessage<ForID, E>,
): string {
let str = `event: ${msg.event}\ndata:`;
if (msg.data) {
str += ' ';
str += JSON.stringify(msg.data);
}
str += '\n\n';
return str;
}
/** @category Common */
export interface ExecutionResult<
Data = Record<string, unknown>,
Extensions = Record<string, unknown>,
> {
errors?: ReadonlyArray<GraphQLError>;
data?: Data | null;
hasNext?: boolean;
extensions?: Extensions;
}
/** @category Common */
export interface ExecutionPatchResult<
Data = unknown,
Extensions = Record<string, unknown>,
> {
errors?: ReadonlyArray<GraphQLError>;
data?: Data | null;
path?: ReadonlyArray<string | number>;
label?: string;
hasNext: boolean;
extensions?: Extensions;
}
/** @category Common */
export type StreamData<E extends StreamEvent> = E extends 'next'
? ExecutionResult | ExecutionPatchResult
: E extends 'complete'
? null
: never;
/** @category Common */
export type StreamDataForID<E extends StreamEvent> = E extends 'next'
? { id: string; payload: ExecutionResult | ExecutionPatchResult }
: E extends 'complete'
? { id: string }
: never;
/** @category Common */
export function parseStreamData<ForID extends boolean, E extends StreamEvent>(
e: E,
data: string,
) {
if (data) {
try {
data = JSON.parse(data);
} catch {
throw new Error('Invalid stream data');
}
}
if (e === 'next' && !data)
throw new Error('Stream data must be an object for "next" events');
return (data || null) as ForID extends true
? StreamDataForID<E>
: StreamData<E>;
}
/**
* A representation of any set of values over any amount of time.
*
* @category Common
*/
export interface Sink<T = unknown> {
/** Next value arriving. */
next(value: T): void;
/** An error that has occurred. This function "closes" the sink. */
error(error: unknown): void;
/** The sink has completed. This function "closes" the sink. */
complete(): void;
}
/**
* Checks whether the provided value is an async iterable.
*
* @category Common
*/
export function isAsyncIterable<T>(val: unknown): val is AsyncIterable<T> {
return typeof Object(val)[Symbol.asyncIterator] === 'function';
}
/**
* Checks whether the provided value is an async generator.
*
* @category Common
*/
export function isAsyncGenerator<T>(val: unknown): val is AsyncGenerator<T> {
return (
isObject(val) &&
typeof Object(val)[Symbol.asyncIterator] === 'function' &&
typeof val.return === 'function' &&
typeof val.throw === 'function' &&
typeof val.next === 'function'
);
}