UNPKG

graphql-request

Version:

Minimal GraphQL client supporting Node and browsers for scripts or simple apps.

629 lines (614 loc) 19.9 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var graphql = require('graphql'); // src/legacy/classes/ClientError.ts var ClientError = class _ClientError extends Error { response; request; constructor(response, request2) { const message = `${_ClientError.extractMessage(response)}: ${JSON.stringify({ response, request: request2 })}`; super(message); Object.setPrototypeOf(this, _ClientError.prototype); this.response = response; this.request = request2; if (typeof Error.captureStackTrace === `function`) { Error.captureStackTrace(this, _ClientError); } } static extractMessage(response) { return response.errors?.[0]?.message ?? `GraphQL Error (Code: ${String(response.status)})`; } }; // src/lib/prelude.ts var uppercase = (str) => str.toUpperCase(); var callOrIdentity = (value) => { return typeof value === `function` ? value() : value; }; var zip = (a, b) => a.map((k, i) => [k, b[i]]); var HeadersInitToPlainObject = (headers) => { let oHeaders = {}; if (headers instanceof Headers) { oHeaders = HeadersInstanceToPlainObject(headers); } else if (Array.isArray(headers)) { headers.forEach(([name, value]) => { if (name && value !== void 0) { oHeaders[name] = value; } }); } else if (headers) { oHeaders = headers; } return oHeaders; }; var HeadersInstanceToPlainObject = (headers) => { const o = {}; headers.forEach((v, k) => { o[k] = v; }); return o; }; var tryCatch = (fn) => { try { const result = fn(); if (isPromiseLikeValue(result)) { return result.catch((error) => { return errorFromMaybeError(error); }); } return result; } catch (error) { return errorFromMaybeError(error); } }; var errorFromMaybeError = (maybeError) => { if (maybeError instanceof Error) return maybeError; return new Error(String(maybeError)); }; var isPromiseLikeValue = (value) => { return typeof value === `object` && value !== null && `then` in value && typeof value.then === `function` && `catch` in value && typeof value.catch === `function` && `finally` in value && typeof value.finally === `function`; }; var casesExhausted = (value) => { throw new Error(`Unhandled case: ${String(value)}`); }; var isPlainObject = (value) => { return typeof value === `object` && value !== null && !Array.isArray(value); }; // src/legacy/functions/batchRequests.ts var batchRequests = async (...args) => { const params = parseBatchRequestsArgsExtended(args); const client = new GraphQLClient(params.url); return client.batchRequests(params); }; var parseBatchRequestsArgsExtended = (args) => { if (args.length === 1) { return args[0]; } else { return { url: args[0], documents: args[1], requestHeaders: args[2], signal: void 0 }; } }; var parseBatchRequestArgs = (documentsOrOptions, requestHeaders) => { return documentsOrOptions.documents ? documentsOrOptions : { documents: documentsOrOptions, requestHeaders, signal: void 0 }; }; // src/legacy/functions/rawRequest.ts var rawRequest = async (...args) => { const [urlOrOptions, query, ...variablesAndRequestHeaders] = args; const requestOptions = parseRawRequestExtendedArgs(urlOrOptions, query, ...variablesAndRequestHeaders); const client = new GraphQLClient(requestOptions.url); return client.rawRequest({ ...requestOptions }); }; var parseRawRequestExtendedArgs = (urlOrOptions, query, ...variablesAndRequestHeaders) => { const [variables, requestHeaders] = variablesAndRequestHeaders; return typeof urlOrOptions === `string` ? { url: urlOrOptions, query, variables, requestHeaders, signal: void 0 } : urlOrOptions; }; var parseRawRequestArgs = (queryOrOptions, variables, requestHeaders) => { return queryOrOptions.query ? queryOrOptions : { query: queryOrOptions, variables, requestHeaders, signal: void 0 }; }; // src/lib/http.ts var ACCEPT_HEADER = `Accept`; var CONTENT_TYPE_HEADER = `Content-Type`; var CONTENT_TYPE_JSON = `application/json`; var CONTENT_TYPE_GQL = `application/graphql-response+json`; // src/legacy/lib/graphql.ts var cleanQuery = (str) => str.replace(/([\s,]|#[^\n\r]+)+/g, ` `).trim(); var isGraphQLContentType = (contentType) => { const contentTypeLower = contentType.toLowerCase(); return contentTypeLower.includes(CONTENT_TYPE_GQL) || contentTypeLower.includes(CONTENT_TYPE_JSON); }; var parseGraphQLExecutionResult = (result) => { try { if (Array.isArray(result)) { return { _tag: `Batch`, executionResults: result.map(parseExecutionResult) }; } else if (isPlainObject(result)) { return { _tag: `Single`, executionResult: parseExecutionResult(result) }; } else { throw new Error(`Invalid execution result: result is not object or array. Got: ${String(result)}`); } } catch (e) { return e; } }; var parseExecutionResult = (result) => { if (typeof result !== `object` || result === null) { throw new Error(`Invalid execution result: result is not object`); } let errors = void 0; let data = void 0; let extensions = void 0; if (`errors` in result) { if (!isPlainObject(result.errors) && !Array.isArray(result.errors)) { throw new Error(`Invalid execution result: errors is not plain object OR array`); } errors = result.errors; } if (`data` in result) { if (!isPlainObject(result.data) && result.data !== null) { throw new Error(`Invalid execution result: data is not plain object`); } data = result.data; } if (`extensions` in result) { if (!isPlainObject(result.extensions)) throw new Error(`Invalid execution result: extensions is not plain object`); extensions = result.extensions; } return { data, errors, extensions }; }; var isRequestResultHaveErrors = (result) => result._tag === `Batch` ? result.executionResults.some(isExecutionResultHaveErrors) : isExecutionResultHaveErrors(result.executionResult); var isExecutionResultHaveErrors = (result) => Array.isArray(result.errors) ? result.errors.length > 0 : Boolean(result.errors); var isOperationDefinitionNode = (definition) => { return typeof definition === `object` && definition !== null && `kind` in definition && definition.kind === graphql.Kind.OPERATION_DEFINITION; }; var extractOperationName = (document) => { let operationName = void 0; const defs = document.definitions.filter(isOperationDefinitionNode); if (defs.length === 1) { operationName = defs[0].name?.value; } return operationName; }; var extractIsMutation = (document) => { let isMutation = false; const defs = document.definitions.filter(isOperationDefinitionNode); if (defs.length === 1) { isMutation = defs[0].operation === `mutation`; } return isMutation; }; var analyzeDocument = (document, excludeOperationName) => { const expression = typeof document === `string` ? document : graphql.print(document); let isMutation = false; let operationName = void 0; if (excludeOperationName) { return { expression, isMutation, operationName }; } const docNode = tryCatch(() => typeof document === `string` ? graphql.parse(document) : document); if (docNode instanceof Error) { return { expression, isMutation, operationName }; } operationName = extractOperationName(docNode); isMutation = extractIsMutation(docNode); return { expression, operationName, isMutation }; }; // src/legacy/helpers/defaultJsonSerializer.ts var defaultJsonSerializer = JSON; // src/legacy/helpers/runRequest.ts var runRequest = async (input) => { const config = { ...input, method: input.request._tag === `Single` ? input.request.document.isMutation ? `POST` : uppercase(input.method ?? `post`) : input.request.hasMutations ? `POST` : uppercase(input.method ?? `post`), fetchOptions: { ...input.fetchOptions, errorPolicy: input.fetchOptions.errorPolicy ?? `none` } }; const fetcher = createFetcher(config.method); const fetchResponse = await fetcher(config); if (!fetchResponse.ok) { return new ClientError( { status: fetchResponse.status, headers: fetchResponse.headers }, { query: input.request._tag === `Single` ? input.request.document.expression : input.request.query, variables: input.request.variables } ); } const result = await parseResultFromResponse( fetchResponse, input.fetchOptions.jsonSerializer ?? defaultJsonSerializer ); if (result instanceof Error) throw result; const clientResponseBase = { status: fetchResponse.status, headers: fetchResponse.headers }; if (isRequestResultHaveErrors(result) && config.fetchOptions.errorPolicy === `none`) { const clientResponse = result._tag === `Batch` ? { ...result.executionResults, ...clientResponseBase } : { ...result.executionResult, ...clientResponseBase }; return new ClientError(clientResponse, { query: input.request._tag === `Single` ? input.request.document.expression : input.request.query, variables: input.request.variables }); } switch (result._tag) { case `Single`: return { ...clientResponseBase, ...executionResultClientResponseFields(config)(result.executionResult) }; case `Batch`: return { ...clientResponseBase, data: result.executionResults.map(executionResultClientResponseFields(config)) }; default: casesExhausted(result); } }; var executionResultClientResponseFields = ($params) => (executionResult) => { return { extensions: executionResult.extensions, data: executionResult.data, errors: $params.fetchOptions.errorPolicy === `all` ? executionResult.errors : void 0 }; }; var parseResultFromResponse = async (response, jsonSerializer) => { const contentType = response.headers.get(CONTENT_TYPE_HEADER); const text = await response.text(); if (contentType && isGraphQLContentType(contentType)) { return parseGraphQLExecutionResult(jsonSerializer.parse(text)); } else { return parseGraphQLExecutionResult(text); } }; var createFetcher = (method) => async (params) => { const headers = new Headers(params.headers); let searchParams = null; let body = void 0; if (!headers.has(ACCEPT_HEADER)) { headers.set(ACCEPT_HEADER, [CONTENT_TYPE_GQL, CONTENT_TYPE_JSON].join(`, `)); } if (method === `POST`) { const $jsonSerializer = params.fetchOptions.jsonSerializer ?? defaultJsonSerializer; body = $jsonSerializer.stringify(buildBody(params)); if (typeof body === `string` && !headers.has(CONTENT_TYPE_HEADER)) { headers.set(CONTENT_TYPE_HEADER, CONTENT_TYPE_JSON); } } else { searchParams = buildQueryParams(params); } const init = { method, headers, body, ...params.fetchOptions }; let url = new URL(params.url); let initResolved = init; if (params.middleware) { const result = await Promise.resolve( params.middleware({ ...init, url: params.url, operationName: params.request._tag === `Single` ? params.request.document.operationName : void 0, variables: params.request.variables }) ); const { url: urlNew, ...initNew } = result; url = new URL(urlNew); initResolved = initNew; } if (searchParams) { searchParams.forEach((value, name) => { url.searchParams.append(name, value); }); } const $fetch = params.fetch ?? fetch; return await $fetch(url, initResolved); }; var buildBody = (params) => { switch (params.request._tag) { case `Single`: return { query: params.request.document.expression, variables: params.request.variables, operationName: params.request.document.operationName }; case `Batch`: return zip(params.request.query, params.request.variables ?? []).map(([query, variables]) => ({ query, variables })); default: throw casesExhausted(params.request); } }; var buildQueryParams = (params) => { const $jsonSerializer = params.fetchOptions.jsonSerializer ?? defaultJsonSerializer; const searchParams = new URLSearchParams(); switch (params.request._tag) { case `Single`: { searchParams.append(`query`, cleanQuery(params.request.document.expression)); if (params.request.variables) { searchParams.append(`variables`, $jsonSerializer.stringify(params.request.variables)); } if (params.request.document.operationName) { searchParams.append(`operationName`, params.request.document.operationName); } return searchParams; } case `Batch`: { const variablesSerialized = params.request.variables?.map((v) => $jsonSerializer.stringify(v)) ?? []; const queriesCleaned = params.request.query.map(cleanQuery); const payload = zip(queriesCleaned, variablesSerialized).map(([query, variables]) => ({ query, variables })); searchParams.append(`query`, $jsonSerializer.stringify(payload)); return searchParams; } default: throw casesExhausted(params.request); } }; // src/legacy/classes/GraphQLClient.ts var GraphQLClient = class { constructor(url, requestConfig = {}) { this.url = url; this.requestConfig = requestConfig; } /** * Send a GraphQL query to the server. */ rawRequest = async (...args) => { const [queryOrOptions, variables, requestHeaders] = args; const rawRequestOptions = parseRawRequestArgs( queryOrOptions, variables, requestHeaders ); const { headers, fetch: fetch2 = globalThis.fetch, method = `POST`, requestMiddleware, responseMiddleware, excludeOperationName, ...fetchOptions } = this.requestConfig; const { url } = this; if (rawRequestOptions.signal !== void 0) { fetchOptions.signal = rawRequestOptions.signal; } const document = analyzeDocument( rawRequestOptions.query, excludeOperationName ); const response = await runRequest({ url, request: { _tag: `Single`, document, variables: rawRequestOptions.variables }, headers: { ...HeadersInitToPlainObject(callOrIdentity(headers)), ...HeadersInitToPlainObject(rawRequestOptions.requestHeaders) }, fetch: fetch2, method, fetchOptions, middleware: requestMiddleware }); if (responseMiddleware) { await responseMiddleware(response, { operationName: document.operationName, variables, url: this.url }); } if (response instanceof Error) { throw response; } return response; }; async request(documentOrOptions, ...variablesAndRequestHeaders) { const [variables, requestHeaders] = variablesAndRequestHeaders; const requestOptions = parseRequestArgs( documentOrOptions, variables, requestHeaders ); const { headers, fetch: fetch2 = globalThis.fetch, method = `POST`, requestMiddleware, responseMiddleware, excludeOperationName, ...fetchOptions } = this.requestConfig; const { url } = this; if (requestOptions.signal !== void 0) { fetchOptions.signal = requestOptions.signal; } const analyzedDocument = analyzeDocument( requestOptions.document, excludeOperationName ); const response = await runRequest({ url, request: { _tag: `Single`, document: analyzedDocument, variables: requestOptions.variables }, headers: { ...HeadersInitToPlainObject(callOrIdentity(headers)), ...HeadersInitToPlainObject(requestOptions.requestHeaders) }, fetch: fetch2, method, fetchOptions, middleware: requestMiddleware }); if (responseMiddleware) { await responseMiddleware(response, { operationName: analyzedDocument.operationName, variables: requestOptions.variables, url: this.url }); } if (response instanceof Error) { throw response; } return response.data; } async batchRequests(documentsOrOptions, requestHeaders) { const batchRequestOptions = parseBatchRequestArgs( documentsOrOptions, requestHeaders ); const { headers, excludeOperationName, ...fetchOptions } = this.requestConfig; if (batchRequestOptions.signal !== void 0) { fetchOptions.signal = batchRequestOptions.signal; } const analyzedDocuments = batchRequestOptions.documents.map( ({ document }) => analyzeDocument(document, excludeOperationName) ); const expressions = analyzedDocuments.map(({ expression }) => expression); const hasMutations = analyzedDocuments.some(({ isMutation }) => isMutation); const variables = batchRequestOptions.documents.map( ({ variables: variables2 }) => variables2 ); const response = await runRequest({ url: this.url, request: { _tag: `Batch`, operationName: void 0, query: expressions, hasMutations, variables }, headers: { ...HeadersInitToPlainObject(callOrIdentity(headers)), ...HeadersInitToPlainObject(batchRequestOptions.requestHeaders) }, fetch: this.requestConfig.fetch ?? globalThis.fetch, method: this.requestConfig.method || `POST`, fetchOptions, middleware: this.requestConfig.requestMiddleware }); if (this.requestConfig.responseMiddleware) { await this.requestConfig.responseMiddleware(response, { operationName: void 0, variables, url: this.url }); } if (response instanceof Error) { throw response; } return response.data; } setHeaders(headers) { this.requestConfig.headers = headers; return this; } /** * Attach a header to the client. All subsequent requests will have this header. */ setHeader(key, value) { const { headers } = this.requestConfig; if (headers) { headers[key] = value; } else { this.requestConfig.headers = { [key]: value }; } return this; } /** * Change the client endpoint. All subsequent requests will send to this endpoint. */ setEndpoint(value) { this.url = value; return this; } }; // src/legacy/functions/request.ts async function request(urlOrOptions, document, ...variablesAndRequestHeaders) { const requestOptions = parseRequestExtendedArgs(urlOrOptions, document, ...variablesAndRequestHeaders); const client = new GraphQLClient(requestOptions.url); return client.request({ ...requestOptions }); } var parseRequestArgs = (documentOrOptions, variables, requestHeaders) => { return documentOrOptions.document ? documentOrOptions : { document: documentOrOptions, variables, requestHeaders, signal: void 0 }; }; var parseRequestExtendedArgs = (urlOrOptions, document, ...variablesAndRequestHeaders) => { const [variables, requestHeaders] = variablesAndRequestHeaders; return typeof urlOrOptions === `string` ? { url: urlOrOptions, document, variables, requestHeaders, signal: void 0 } : urlOrOptions; }; // src/legacy/functions/gql.ts var gql = (chunks, ...variables) => { return chunks.reduce( (acc, chunk, index) => `${acc}${chunk}${index in variables ? String(variables[index]) : ``}`, `` ); }; // src/entrypoints/main.ts var main_default = request; exports.ClientError = ClientError; exports.GraphQLClient = GraphQLClient; exports.analyzeDocument = analyzeDocument; exports.batchRequests = batchRequests; exports.default = main_default; exports.gql = gql; exports.rawRequest = rawRequest; exports.request = request; //# sourceMappingURL=main.cjs.map //# sourceMappingURL=main.cjs.map