twenty-sdk 0.6.0 → 0.6.2

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 (70) hide show
  1. package/README.md +6 -2
  2. package/dist/{HtmlTagToRemoteComponent-DzQ2I9Lz.js → HtmlTagToRemoteComponent-CgtwxDeH.js} +11 -11
  3. package/dist/{HtmlTagToRemoteComponent-DBOkvIRB.mjs → HtmlTagToRemoteComponent-D_EW5OLu.mjs} +1743 -1640
  4. package/dist/cli/utilities/api/api-service.d.ts +4 -0
  5. package/dist/cli/utilities/build/common/esbuild-watcher.d.ts +5 -2
  6. package/dist/cli/utilities/build/common/typecheck-plugin.d.ts +1 -1
  7. package/dist/cli/utilities/build/manifest/manifest-extract-config.d.ts +2 -0
  8. package/dist/cli/utilities/client/client-service.d.ts +5 -1
  9. package/dist/cli/utilities/client/twenty-client-template.d.ts +42 -0
  10. package/dist/cli/utilities/dev/orchestrator/dev-mode-orchestrator.d.ts +2 -0
  11. package/dist/cli/utilities/dev/orchestrator/steps/start-watchers-orchestrator-step.d.ts +2 -0
  12. package/dist/cli.cjs +430 -75
  13. package/dist/cli.mjs +3175 -2725
  14. package/dist/front-component-renderer/index.cjs +11 -11
  15. package/dist/front-component-renderer/index.d.ts +3 -3
  16. package/dist/front-component-renderer/index.mjs +2186 -1906
  17. package/dist/front-component-renderer/remote/generated/remote-components.d.ts +44 -0
  18. package/dist/front-component-renderer/remote/generated/remote-elements.d.ts +93 -0
  19. package/dist/front-component-renderer/types/FrontComponentHostCommunicationApi.d.ts +2 -1
  20. package/dist/{get-function-input-schema-BZ7_XyUh-GxSybvDe.js → get-function-input-schema-BZ7_XyUh-CCSi0u_q.js} +1 -1
  21. package/dist/{get-function-input-schema-BZ7_XyUh-By3UDh4s.mjs → get-function-input-schema-BZ7_XyUh-DAPandzB.mjs} +1 -1
  22. package/dist/index.cjs +2 -2
  23. package/dist/index.mjs +122 -89
  24. package/dist/sdk/application/application-config.d.ts +1 -1
  25. package/dist/sdk/front-component-api/constants/AllowedHtmlElements.d.ts +1 -0
  26. package/dist/sdk/front-component-api/constants/AllowedHtmlElements.js +104 -1
  27. package/dist/sdk/front-component-api/constants/AllowedHtmlElements.js.map +1 -1
  28. package/dist/sdk/front-component-api/constants/EventToReact.js +22 -3
  29. package/dist/sdk/front-component-api/constants/EventToReact.js.map +1 -1
  30. package/dist/sdk/front-component-api/constants/SerializedEventData.d.ts +7 -0
  31. package/dist/sdk/front-component-api/globals/frontComponentHostCommunicationApi.d.ts +2 -0
  32. package/dist/sdk/front-component-api/globals/frontComponentHostCommunicationApi.js.map +1 -1
  33. package/dist/sdk/index.d.ts +3 -0
  34. package/dist/sdk/index.js +70 -66
  35. package/dist/sdk/index.js.map +1 -1
  36. package/dist/sdk/logic-functions/define-post-install-logic-function.d.ts +6 -0
  37. package/dist/sdk/logic-functions/define-post-install-logic-function.js +12 -0
  38. package/dist/sdk/logic-functions/define-post-install-logic-function.js.map +1 -0
  39. package/dist/sdk/logic-functions/define-pre-install-logic-function.d.ts +6 -0
  40. package/dist/sdk/logic-functions/define-pre-install-logic-function.js +12 -0
  41. package/dist/sdk/logic-functions/define-pre-install-logic-function.js.map +1 -0
  42. package/dist/sdk/logic-functions/install-logic-function-payload-type.d.ts +4 -0
  43. package/generated/core/index.ts +406 -0
  44. package/generated/core/runtime/batcher.ts +265 -0
  45. package/generated/core/runtime/createClient.ts +68 -0
  46. package/generated/core/runtime/error.ts +29 -0
  47. package/generated/core/runtime/fetcher.ts +98 -0
  48. package/generated/core/runtime/generateGraphqlOperation.ts +225 -0
  49. package/generated/core/runtime/index.ts +13 -0
  50. package/generated/core/runtime/linkTypeMap.ts +139 -0
  51. package/generated/core/runtime/typeSelection.ts +98 -0
  52. package/generated/core/runtime/types.ts +69 -0
  53. package/generated/core/schema.graphql +36745 -0
  54. package/generated/core/schema.ts +39341 -0
  55. package/generated/core/types.ts +45860 -0
  56. package/generated/index.ts +2 -0
  57. package/generated/metadata/index.ts +469 -0
  58. package/generated/metadata/runtime/batcher.ts +265 -0
  59. package/generated/metadata/runtime/createClient.ts +68 -0
  60. package/generated/metadata/runtime/error.ts +29 -0
  61. package/generated/metadata/runtime/fetcher.ts +98 -0
  62. package/generated/metadata/runtime/generateGraphqlOperation.ts +225 -0
  63. package/generated/metadata/runtime/index.ts +13 -0
  64. package/generated/metadata/runtime/linkTypeMap.ts +139 -0
  65. package/generated/metadata/runtime/typeSelection.ts +98 -0
  66. package/generated/metadata/runtime/types.ts +69 -0
  67. package/generated/metadata/schema.graphql +3971 -0
  68. package/generated/metadata/schema.ts +8357 -0
  69. package/generated/metadata/types.ts +10044 -0
  70. package/package.json +17 -1
@@ -0,0 +1,406 @@
1
+ // @ts-nocheck
2
+ import type {
3
+ QueryGenqlSelection,
4
+ Query,
5
+ MutationGenqlSelection,
6
+ Mutation,
7
+ } from './schema'
8
+ import {
9
+ linkTypeMap,
10
+ createClient as createClientOriginal,
11
+ generateGraphqlOperation,
12
+ type FieldsSelection,
13
+ type GraphqlOperation,
14
+ type ClientOptions,
15
+ GenqlError,
16
+ } from './runtime'
17
+ export type { FieldsSelection } from './runtime'
18
+ export { GenqlError }
19
+
20
+ import types from './types'
21
+ export * from './schema'
22
+ const typeMap = linkTypeMap(types as any)
23
+
24
+ export interface Client {
25
+ query<R extends QueryGenqlSelection>(
26
+ request: R & { __name?: string },
27
+ ): Promise<FieldsSelection<Query, R>>
28
+
29
+ mutation<R extends MutationGenqlSelection>(
30
+ request: R & { __name?: string },
31
+ ): Promise<FieldsSelection<Mutation, R>>
32
+ }
33
+
34
+ export const createClient = function (options?: ClientOptions): Client {
35
+ return createClientOriginal({
36
+ url: undefined,
37
+
38
+ ...options,
39
+ queryRoot: typeMap.Query!,
40
+ mutationRoot: typeMap.Mutation!,
41
+ subscriptionRoot: typeMap.Subscription!,
42
+ }) as any
43
+ }
44
+
45
+ export const everything = {
46
+ __scalar: true,
47
+ }
48
+
49
+ export type QueryResult<fields extends QueryGenqlSelection> = FieldsSelection<
50
+ Query,
51
+ fields
52
+ >
53
+ export const generateQueryOp: (
54
+ fields: QueryGenqlSelection & { __name?: string },
55
+ ) => GraphqlOperation = function (fields) {
56
+ return generateGraphqlOperation('query', typeMap.Query!, fields as any)
57
+ }
58
+
59
+ export type MutationResult<fields extends MutationGenqlSelection> =
60
+ FieldsSelection<Mutation, fields>
61
+ export const generateMutationOp: (
62
+ fields: MutationGenqlSelection & { __name?: string },
63
+ ) => GraphqlOperation = function (fields) {
64
+ return generateGraphqlOperation('mutation', typeMap.Mutation!, fields as any)
65
+ }
66
+
67
+
68
+ // ----------------------------------------------------
69
+ // CoreApiClient (auto-injected)
70
+ // ----------------------------------------------------
71
+
72
+ const APP_ACCESS_TOKEN_ENV_KEY = 'TWENTY_APP_ACCESS_TOKEN';
73
+ const API_KEY_ENV_KEY = 'TWENTY_API_KEY';
74
+
75
+ type CoreApiClientOptions = ClientOptions
76
+
77
+ type ProcessEnvironment = Record<string, string | undefined>
78
+
79
+ type GraphqlError = {
80
+ message?: string;
81
+ extensions?: { code?: string };
82
+ }
83
+
84
+ type GraphqlResponsePayload = {
85
+ data?: Record<string, unknown>
86
+ errors?: GraphqlError[];
87
+ }
88
+
89
+ type GraphqlResponse = {
90
+ status: number;
91
+ statusText: string;
92
+ payload: GraphqlResponsePayload | null;
93
+ rawBody: string;
94
+ }
95
+
96
+ const getProcessEnvironment = (): ProcessEnvironment => {
97
+ const processObject = (globalThis as { process?: { env?: ProcessEnvironment } })
98
+ .process;
99
+
100
+ return processObject?.env ?? {};
101
+ }
102
+
103
+ const getTokenFromAuthorizationHeader = (
104
+ authorizationHeader: string | undefined,
105
+ ): string | null => {
106
+ if (typeof authorizationHeader !== 'string') {
107
+ return null;
108
+ }
109
+
110
+ const trimmedAuthorizationHeader = authorizationHeader.trim();
111
+
112
+ if (trimmedAuthorizationHeader.length === 0) {
113
+ return null;
114
+ }
115
+
116
+ if (trimmedAuthorizationHeader === 'Bearer') {
117
+ return null;
118
+ }
119
+
120
+ if (trimmedAuthorizationHeader.startsWith('Bearer ')) {
121
+ return trimmedAuthorizationHeader.slice('Bearer '.length).trim();
122
+ }
123
+
124
+ return trimmedAuthorizationHeader;
125
+ }
126
+
127
+ const getTokenFromHeaders = (headers: HeadersInit | undefined): string | null => {
128
+ if (!headers) {
129
+ return null;
130
+ }
131
+
132
+ if (headers instanceof Headers) {
133
+ return getTokenFromAuthorizationHeader(headers.get('Authorization') ?? undefined);
134
+ }
135
+
136
+ if (Array.isArray(headers)) {
137
+ const matchedAuthorizationHeader = headers.find(
138
+ ([headerName]) => headerName.toLowerCase() === 'authorization',
139
+ );
140
+
141
+ return getTokenFromAuthorizationHeader(matchedAuthorizationHeader?.[1]);
142
+ }
143
+
144
+ const headersRecord = headers as Record<string, string | undefined>;
145
+
146
+ return getTokenFromAuthorizationHeader(
147
+ headersRecord.Authorization ?? headersRecord.authorization,
148
+ );
149
+ }
150
+
151
+ const hasAuthenticationErrorInGraphqlPayload = (
152
+ payload: GraphqlResponsePayload | null,
153
+ ): boolean => {
154
+ if (!payload?.errors) {
155
+ return false;
156
+ }
157
+
158
+ return payload.errors.some((error) => {
159
+ return (
160
+ error.extensions?.code === 'UNAUTHENTICATED' ||
161
+ error.message?.toLowerCase() === 'unauthorized'
162
+ );
163
+ });
164
+ }
165
+
166
+ const defaultOptions: CoreApiClientOptions = {
167
+ url: `${process.env.TWENTY_API_URL}/graphql`,
168
+ headers: {
169
+ 'Content-Type': 'application/json',
170
+ },
171
+ }
172
+
173
+ export class CoreApiClient {
174
+ private client: Client;
175
+ private url: string;
176
+ private requestOptions: RequestInit;
177
+ private headers: HeadersInit | (() => HeadersInit | Promise<HeadersInit>);
178
+ private fetchImplementation: typeof globalThis.fetch | null;
179
+ private authorizationToken: string | null;
180
+ private refreshAccessTokenPromise: Promise<string | null> | null = null;
181
+
182
+ constructor(options?: CoreApiClientOptions) {
183
+ const merged: CoreApiClientOptions = {
184
+ ...defaultOptions,
185
+ ...options,
186
+ }
187
+
188
+ const {
189
+ url,
190
+ headers,
191
+ fetch: customFetchImplementation,
192
+ fetcher: _fetcher,
193
+ batch: _batch,
194
+ ...requestOptions
195
+ } = merged;
196
+
197
+ this.url = url ?? '';
198
+ this.requestOptions = requestOptions;
199
+ this.headers = headers ?? {};
200
+ this.fetchImplementation = customFetchImplementation ?? globalThis.fetch ?? null;
201
+
202
+ const processEnvironment = getProcessEnvironment();
203
+ const tokenFromHeaders = getTokenFromHeaders(
204
+ typeof headers === 'function' ? undefined : headers,
205
+ );
206
+
207
+ // Priority: explicit header > TWENTY_APP_ACCESS_TOKEN > TWENTY_API_KEY (legacy fallback).
208
+ this.authorizationToken =
209
+ tokenFromHeaders ??
210
+ processEnvironment[APP_ACCESS_TOKEN_ENV_KEY] ??
211
+ processEnvironment[API_KEY_ENV_KEY] ??
212
+ null;
213
+
214
+ this.client = createClient({
215
+ ...merged,
216
+ headers: undefined,
217
+ fetcher: async (operation) =>
218
+ this.executeGraphqlRequestWithOptionalRefresh({
219
+ operation,
220
+ }),
221
+ });
222
+ }
223
+
224
+ query<R extends QueryGenqlSelection>(request: R & { __name?: string }) {
225
+ return this.client.query(request);
226
+ }
227
+
228
+ mutation<R extends MutationGenqlSelection>(request: R & { __name?: string }) {
229
+ return this.client.mutation(request);
230
+ }
231
+
232
+ private async executeGraphqlRequestWithOptionalRefresh({
233
+ operation,
234
+ headers,
235
+ requestInit,
236
+ }: {
237
+ operation: GraphqlOperation | GraphqlOperation[] | FormData;
238
+ headers?: HeadersInit;
239
+ requestInit?: RequestInit;
240
+ }) {
241
+ const firstResponse = await this.executeGraphqlRequest({
242
+ operation,
243
+ headers,
244
+ requestInit,
245
+ token: this.authorizationToken,
246
+ });
247
+
248
+ if (this.shouldRefreshToken(firstResponse)) {
249
+ const refreshedAccessToken = await this.requestRefreshedAccessToken();
250
+
251
+ if (refreshedAccessToken) {
252
+ const retryResponse = await this.executeGraphqlRequest({
253
+ operation,
254
+ headers,
255
+ requestInit,
256
+ token: refreshedAccessToken,
257
+ });
258
+
259
+ return this.assertResponseIsSuccessful(retryResponse);
260
+ }
261
+ }
262
+
263
+ return this.assertResponseIsSuccessful(firstResponse);
264
+ }
265
+
266
+ private async executeGraphqlRequest({
267
+ operation,
268
+ headers,
269
+ requestInit,
270
+ token,
271
+ }: {
272
+ operation: GraphqlOperation | GraphqlOperation[] | FormData;
273
+ headers?: HeadersInit;
274
+ requestInit?: RequestInit;
275
+ token: string | null;
276
+ }): Promise<GraphqlResponse> {
277
+ if (!this.fetchImplementation) {
278
+ throw new Error(
279
+ 'Global `fetch` function is not available, pass a fetch implementation to the Twenty client',
280
+ );
281
+ }
282
+
283
+ const resolvedHeaders = await this.resolveHeaders();
284
+ const requestHeaders = new Headers(resolvedHeaders);
285
+
286
+ if (headers) {
287
+ new Headers(headers).forEach((value, key) => requestHeaders.set(key, value));
288
+ }
289
+
290
+ if (operation instanceof FormData) {
291
+ requestHeaders.delete('Content-Type');
292
+ } else {
293
+ requestHeaders.set('Content-Type', 'application/json');
294
+ }
295
+
296
+ if (token) {
297
+ requestHeaders.set('Authorization', `Bearer ${token}`);
298
+ } else {
299
+ requestHeaders.delete('Authorization');
300
+ }
301
+
302
+ const response = await this.fetchImplementation.call(globalThis, this.url, {
303
+ ...this.requestOptions,
304
+ ...requestInit,
305
+ method: requestInit?.method ?? 'POST',
306
+ headers: requestHeaders,
307
+ body: operation instanceof FormData ? operation : JSON.stringify(operation),
308
+ });
309
+
310
+ const rawBody = await response.text();
311
+ let payload: GraphqlResponsePayload | null = null;
312
+
313
+ if (rawBody.trim().length > 0) {
314
+ try {
315
+ payload = JSON.parse(rawBody) as GraphqlResponsePayload;
316
+ } catch {
317
+ payload = null;
318
+ }
319
+ }
320
+
321
+ return {
322
+ status: response.status,
323
+ statusText: response.statusText,
324
+ payload,
325
+ rawBody,
326
+ }
327
+ }
328
+
329
+ private async resolveHeaders(): Promise<HeadersInit> {
330
+ if (typeof this.headers === 'function') {
331
+ return (await this.headers()) ?? {};
332
+ }
333
+
334
+ return this.headers ?? {};
335
+ }
336
+
337
+ private shouldRefreshToken(response: GraphqlResponse): boolean {
338
+ if (response.status === 401) {
339
+ return true;
340
+ }
341
+
342
+ return hasAuthenticationErrorInGraphqlPayload(response.payload);
343
+ }
344
+
345
+ private assertResponseIsSuccessful(response: GraphqlResponse) {
346
+ if (response.status < 200 || response.status >= 300) {
347
+ throw new Error(`${response.statusText}: ${response.rawBody}`);
348
+ }
349
+
350
+ if (response.payload === null) {
351
+ throw new Error('Invalid JSON response');
352
+ }
353
+
354
+ return response.payload;
355
+ }
356
+
357
+ private async requestRefreshedAccessToken(): Promise<string | null> {
358
+ const refreshAccessTokenFunction = (
359
+ globalThis as {
360
+ frontComponentHostCommunicationApi?: {
361
+ requestAccessTokenRefresh?: () => Promise<string>
362
+ }
363
+ }
364
+ ).frontComponentHostCommunicationApi?.requestAccessTokenRefresh;
365
+
366
+ if (typeof refreshAccessTokenFunction !== 'function') {
367
+ return null;
368
+ }
369
+
370
+ if (!this.refreshAccessTokenPromise) {
371
+ this.refreshAccessTokenPromise = refreshAccessTokenFunction()
372
+ .then((refreshedAccessToken) => {
373
+ if (
374
+ typeof refreshedAccessToken !== 'string' ||
375
+ refreshedAccessToken.length === 0
376
+ ) {
377
+ return null;
378
+ }
379
+
380
+ this.setAuthorizationToken(refreshedAccessToken);
381
+
382
+ return refreshedAccessToken;
383
+ })
384
+ .catch((error) => {
385
+ console.error('Twenty client: token refresh failed', error);
386
+
387
+ return null;
388
+ })
389
+ .finally(() => {
390
+ this.refreshAccessTokenPromise = null;
391
+ });
392
+ }
393
+
394
+ return this.refreshAccessTokenPromise;
395
+ }
396
+
397
+ private setAuthorizationToken(token: string) {
398
+ this.authorizationToken = token;
399
+
400
+ const processEnvironment = getProcessEnvironment();
401
+
402
+ processEnvironment[APP_ACCESS_TOKEN_ENV_KEY] = token;
403
+ processEnvironment[API_KEY_ENV_KEY] = token;
404
+ }
405
+ }
406
+
@@ -0,0 +1,265 @@
1
+ // @ts-nocheck
2
+ import type { GraphqlOperation } from './generateGraphqlOperation'
3
+ import { GenqlError } from './error'
4
+
5
+ type Variables = Record<string, any>
6
+
7
+ type QueryError = Error & {
8
+ message: string
9
+
10
+ locations?: Array<{
11
+ line: number
12
+ column: number
13
+ }>
14
+ path?: any
15
+ rid: string
16
+ details?: Record<string, any>
17
+ }
18
+ type Result = {
19
+ data: Record<string, any>
20
+ errors: Array<QueryError>
21
+ }
22
+ type Fetcher = (
23
+ batchedQuery: GraphqlOperation | Array<GraphqlOperation>,
24
+ ) => Promise<Array<Result>>
25
+ type Options = {
26
+ batchInterval?: number
27
+ shouldBatch?: boolean
28
+ maxBatchSize?: number
29
+ }
30
+ type Queue = Array<{
31
+ request: GraphqlOperation
32
+ resolve: (...args: Array<any>) => any
33
+ reject: (...args: Array<any>) => any
34
+ }>
35
+
36
+ /**
37
+ * takes a list of requests (queue) and batches them into a single server request.
38
+ * It will then resolve each individual requests promise with the appropriate data.
39
+ * @private
40
+ * @param {QueryBatcher} client - the client to use
41
+ * @param {Queue} queue - the list of requests to batch
42
+ */
43
+ function dispatchQueueBatch(client: QueryBatcher, queue: Queue): void {
44
+ let batchedQuery: any = queue.map((item) => item.request)
45
+
46
+ if (batchedQuery.length === 1) {
47
+ batchedQuery = batchedQuery[0]
48
+ }
49
+
50
+ client.fetcher(batchedQuery).then((responses: any) => {
51
+ if (queue.length === 1 && !Array.isArray(responses)) {
52
+ if (responses.errors && responses.errors.length) {
53
+ queue[0].reject(
54
+ new GenqlError(responses.errors, responses.data),
55
+ )
56
+ return
57
+ }
58
+
59
+ queue[0].resolve(responses)
60
+ return
61
+ } else if (responses.length !== queue.length) {
62
+ throw new Error('response length did not match query length')
63
+ }
64
+
65
+ for (let i = 0; i < queue.length; i++) {
66
+ if (responses[i].errors && responses[i].errors.length) {
67
+ queue[i].reject(
68
+ new GenqlError(responses[i].errors, responses[i].data),
69
+ )
70
+ } else {
71
+ queue[i].resolve(responses[i])
72
+ }
73
+ }
74
+ })
75
+ }
76
+
77
+ /**
78
+ * creates a list of requests to batch according to max batch size.
79
+ * @private
80
+ * @param {QueryBatcher} client - the client to create list of requests from from
81
+ * @param {Options} options - the options for the batch
82
+ */
83
+ function dispatchQueue(client: QueryBatcher, options: Options): void {
84
+ const queue = client._queue
85
+ const maxBatchSize = options.maxBatchSize || 0
86
+ client._queue = []
87
+
88
+ if (maxBatchSize > 0 && maxBatchSize < queue.length) {
89
+ for (let i = 0; i < queue.length / maxBatchSize; i++) {
90
+ dispatchQueueBatch(
91
+ client,
92
+ queue.slice(i * maxBatchSize, (i + 1) * maxBatchSize),
93
+ )
94
+ }
95
+ } else {
96
+ dispatchQueueBatch(client, queue)
97
+ }
98
+ }
99
+ /**
100
+ * Create a batcher client.
101
+ * @param {Fetcher} fetcher - A function that can handle the network requests to graphql endpoint
102
+ * @param {Options} options - the options to be used by client
103
+ * @param {boolean} options.shouldBatch - should the client batch requests. (default true)
104
+ * @param {integer} options.batchInterval - duration (in MS) of each batch window. (default 6)
105
+ * @param {integer} options.maxBatchSize - max number of requests in a batch. (default 0)
106
+ * @param {boolean} options.defaultHeaders - default headers to include with every request
107
+ *
108
+ * @example
109
+ * const fetcher = batchedQuery => fetch('path/to/graphql', {
110
+ * method: 'post',
111
+ * headers: {
112
+ * Accept: 'application/json',
113
+ * 'Content-Type': 'application/json',
114
+ * },
115
+ * body: JSON.stringify(batchedQuery),
116
+ * credentials: 'include',
117
+ * })
118
+ * .then(response => response.json())
119
+ *
120
+ * const client = new QueryBatcher(fetcher, { maxBatchSize: 10 })
121
+ */
122
+
123
+ export class QueryBatcher {
124
+ fetcher: Fetcher
125
+ _options: Options
126
+ _queue: Queue
127
+
128
+ constructor(
129
+ fetcher: Fetcher,
130
+ {
131
+ batchInterval = 6,
132
+ shouldBatch = true,
133
+ maxBatchSize = 0,
134
+ }: Options = {},
135
+ ) {
136
+ this.fetcher = fetcher
137
+ this._options = {
138
+ batchInterval,
139
+ shouldBatch,
140
+ maxBatchSize,
141
+ }
142
+ this._queue = []
143
+ }
144
+
145
+ /**
146
+ * Fetch will send a graphql request and return the parsed json.
147
+ * @param {string} query - the graphql query.
148
+ * @param {Variables} variables - any variables you wish to inject as key/value pairs.
149
+ * @param {[string]} operationName - the graphql operationName.
150
+ * @param {Options} overrides - the client options overrides.
151
+ *
152
+ * @return {promise} resolves to parsed json of server response
153
+ *
154
+ * @example
155
+ * client.fetch(`
156
+ * query getHuman($id: ID!) {
157
+ * human(id: $id) {
158
+ * name
159
+ * height
160
+ * }
161
+ * }
162
+ * `, { id: "1001" }, 'getHuman')
163
+ * .then(human => {
164
+ * // do something with human
165
+ * console.log(human);
166
+ * });
167
+ */
168
+ fetch(
169
+ query: string,
170
+ variables?: Variables,
171
+ operationName?: string,
172
+ overrides: Options = {},
173
+ ): Promise<Result> {
174
+ const request: GraphqlOperation = {
175
+ query,
176
+ }
177
+ const options = Object.assign({}, this._options, overrides)
178
+
179
+ if (variables) {
180
+ request.variables = variables
181
+ }
182
+
183
+ if (operationName) {
184
+ request.operationName = operationName
185
+ }
186
+
187
+ const promise = new Promise<Result>((resolve, reject) => {
188
+ this._queue.push({
189
+ request,
190
+ resolve,
191
+ reject,
192
+ })
193
+
194
+ if (this._queue.length === 1) {
195
+ if (options.shouldBatch) {
196
+ setTimeout(
197
+ () => dispatchQueue(this, options),
198
+ options.batchInterval,
199
+ )
200
+ } else {
201
+ dispatchQueue(this, options)
202
+ }
203
+ }
204
+ })
205
+ return promise
206
+ }
207
+
208
+ /**
209
+ * Fetch will send a graphql request and return the parsed json.
210
+ * @param {string} query - the graphql query.
211
+ * @param {Variables} variables - any variables you wish to inject as key/value pairs.
212
+ * @param {[string]} operationName - the graphql operationName.
213
+ * @param {Options} overrides - the client options overrides.
214
+ *
215
+ * @return {Promise<Array<Result>>} resolves to parsed json of server response
216
+ *
217
+ * @example
218
+ * client.forceFetch(`
219
+ * query getHuman($id: ID!) {
220
+ * human(id: $id) {
221
+ * name
222
+ * height
223
+ * }
224
+ * }
225
+ * `, { id: "1001" }, 'getHuman')
226
+ * .then(human => {
227
+ * // do something with human
228
+ * console.log(human);
229
+ * });
230
+ */
231
+ forceFetch(
232
+ query: string,
233
+ variables?: Variables,
234
+ operationName?: string,
235
+ overrides: Options = {},
236
+ ): Promise<Result> {
237
+ const request: GraphqlOperation = {
238
+ query,
239
+ }
240
+ const options = Object.assign({}, this._options, overrides, {
241
+ shouldBatch: false,
242
+ })
243
+
244
+ if (variables) {
245
+ request.variables = variables
246
+ }
247
+
248
+ if (operationName) {
249
+ request.operationName = operationName
250
+ }
251
+
252
+ const promise = new Promise<Result>((resolve, reject) => {
253
+ const client = new QueryBatcher(this.fetcher, this._options)
254
+ client._queue = [
255
+ {
256
+ request,
257
+ resolve,
258
+ reject,
259
+ },
260
+ ]
261
+ dispatchQueue(client, options)
262
+ })
263
+ return promise
264
+ }
265
+ }