UNPKG

ohmygql

Version:

[![npm version][npm-version-src]][npm-version-href] [![npm downloads][npm-downloads-src]][npm-downloads-href] [![Github Actions][github-actions-src]][github-actions-href] [![Codecov][codecov-src]][codecov-href]

147 lines (142 loc) 4.51 kB
import { print } from 'graphql'; import { $fetch, FetchError } from 'ofetch'; import { extractOperation } from './utils.mjs'; import { createClient } from 'graphql-ws'; class GqlError extends Error { constructor(message, args) { super(message); this.name = "GqlError"; this.status = args.status; this.operation = args.operation; this.gqlErrors = args.gqlErrors; } } function wsClient(options) { let restartRequested = false; let restart = () => { restartRequested = true; }; const client = createClient({ ...options, on: { ...options.on, opened: (socket) => { options.on?.opened?.(socket); restart = () => { if (socket.readyState === WebSocket.OPEN) { socket.close(4205, "Client Restart"); } else { restartRequested = true; } }; if (restartRequested) { restartRequested = false; restart(); } } } }); return { ...client, restart: () => restart() }; } const GqlClient = (input) => { const opts = typeof input === "string" ? { host: input } : input; let fetchOptions = {}; const setHost = (host) => { if (!host) { return; } opts.host = host; }; const setOptions = (opts2) => { if (!opts2) { fetchOptions = {}; return; } for (const [k, v] of Object.entries(opts2)) { if (!v) { delete fetchOptions[k]; continue; } fetchOptions[k] = typeof v !== "object" ? v : { ...fetchOptions[k], ...v }; } }; const setHeaders = (headers) => setOptions({ headers }); const setMiddleware = (mw) => { if (!mw) { return; } opts.middleware = opts.middleware || {}; for (const [k, v] of Object.entries(mw)) { opts.middleware[k] = v; } }; async function execute(...args) { let query = args?.[0]?.query || args?.[0]; query = typeof query === "string" ? query : print(query); const variables = args?.[0]?.variables || args?.[1]; fetchOptions.headers = fetchOptions?.headers || {}; fetchOptions.headers = { ...opts?.headers, ...args?.[0]?.headers || args?.[2], ...fetchOptions?.headers }; const useGET = opts?.useGETForQueries && extractOperation(query)?.type === "query"; const reqOptions = { query, ...variables && { variables: !useGET ? variables : JSON.stringify(variables) } }; const res = await $fetch.raw(opts.host, { ...!useGET && { method: "POST" }, ...fetchOptions, headers: { "Content-Type": "application/json", ...fetchOptions?.headers }, ...opts?.middleware, ...!useGET ? { body: reqOptions } : { params: reqOptions } }).catch((e) => e); if (res instanceof FetchError || res?._data?.errors) { const gqlErrors = (res instanceof FetchError ? res.data?.errors : res._data?.errors) || void 0; const response = res instanceof FetchError ? res.response : res; const status = response?.status; const message = gqlErrors?.map((e) => e.message).join(", ") || response && `${status} ${response?.statusText}` || "Fetch failed"; throw new GqlError(message, { status, gqlErrors, operation: extractOperation(query) }); } return res._data?.data; } function subscribe(...args) { let query = args?.[0]?.query || args?.[0]; query = typeof query === "string" ? query : print(query); const variables = args?.[0]?.variables || args?.[1]; const options = args?.[0]?.options || args?.[2]; const url = opts?.wsHost || opts?.host.replace(/^http/, "ws").replace(/^https/, "wss"); if (!url || !url.startsWith("ws")) { throw new Error("Invalid websocket host"); } const client = wsClient({ url, ...opts?.wsOptions, ...options }); let unsubscribe = () => { }; let onError; let onResult; let onComplete; return { restart: () => client.restart(), unsubscribe: () => unsubscribe(), onError: (cb) => onError = cb, onResult: (cb) => onResult = cb, onComplete: (cb) => onComplete = cb, subscribe: () => { unsubscribe = client.subscribe({ query, variables }, { next: onResult || (() => { }), error: onError || (() => { }), complete: onComplete || (() => { }) }); } }; } return { execute, subscribe, setHost, setOptions, setHeaders, setMiddleware }; }; export { GqlClient, GqlError };