@mysten/sui
Version:
Sui TypeScript API(Work in Progress)
129 lines (115 loc) • 3.77 kB
text/typescript
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0
import type { TypedDocumentNode } from '@graphql-typed-document-node/core';
import type { TadaDocumentNode } from 'gql.tada';
import type { DocumentNode } from 'graphql';
import { print } from 'graphql';
import { Experimental_BaseClient } from '../experimental/index.js';
import type { Experimental_SuiClientTypes } from '../experimental/index.js';
import { GraphQLTransport } from '../experimental/transports/graphql.js';
import type { TypedDocumentString } from './generated/queries.js';
export type GraphQLDocument<
Result = Record<string, unknown>,
Variables = Record<string, unknown>,
> =
| string
| DocumentNode
| TypedDocumentString<Result, Variables>
| TypedDocumentNode<Result, Variables>
| TadaDocumentNode<Result, Variables>;
export type GraphQLQueryOptions<
Result = Record<string, unknown>,
Variables = Record<string, unknown>,
> = {
query: GraphQLDocument<Result, Variables>;
operationName?: string;
extensions?: Record<string, unknown>;
signal?: AbortSignal;
} & (Variables extends { [key: string]: never }
? { variables?: Variables }
: {
variables: Variables;
});
export type GraphQLQueryResult<Result = Record<string, unknown>> = {
data?: Result;
errors?: GraphQLResponseErrors;
extensions?: Record<string, unknown>;
};
export type GraphQLResponseErrors = Array<{
message: string;
locations?: { line: number; column: number }[];
path?: (string | number)[];
}>;
export interface SuiGraphQLClientOptions<Queries extends Record<string, GraphQLDocument>> {
url: string;
fetch?: typeof fetch;
headers?: Record<string, string>;
queries?: Queries;
network?: Experimental_SuiClientTypes.Network;
}
export class SuiGraphQLRequestError extends Error {}
export class SuiGraphQLClient<
// eslint-disable-next-line @typescript-eslint/ban-types
Queries extends Record<string, GraphQLDocument> = {},
> extends Experimental_BaseClient {
#url: string;
#queries: Queries;
#headers: Record<string, string>;
#fetch: typeof fetch;
core: GraphQLTransport = new GraphQLTransport(this);
constructor({
url,
fetch: fetchFn = fetch,
headers = {},
queries = {} as Queries,
network = 'unknown',
}: SuiGraphQLClientOptions<Queries>) {
super({
network,
});
this.#url = url;
this.#queries = queries;
this.#headers = headers;
this.#fetch = (...args) => fetchFn(...args);
}
async query<Result = Record<string, unknown>, Variables = Record<string, unknown>>(
options: GraphQLQueryOptions<Result, Variables>,
): Promise<GraphQLQueryResult<Result>> {
const res = await this.#fetch(this.#url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
...this.#headers,
},
body: JSON.stringify({
query:
typeof options.query === 'string' || options.query instanceof String
? String(options.query)
: print(options.query),
variables: options.variables,
extensions: options.extensions,
operationName: options.operationName,
}),
signal: options.signal,
});
if (!res.ok) {
throw new SuiGraphQLRequestError(`GraphQL request failed: ${res.statusText} (${res.status})`);
}
return await res.json();
}
async execute<
const Query extends Extract<keyof Queries, string>,
Result = Queries[Query] extends GraphQLDocument<infer R, unknown> ? R : Record<string, unknown>,
Variables = Queries[Query] extends GraphQLDocument<unknown, infer V>
? V
: Record<string, unknown>,
>(
query: Query,
options: Omit<GraphQLQueryOptions<Result, Variables>, 'query'>,
): Promise<GraphQLQueryResult<Result>> {
return this.query({
...(options as { variables: Record<string, unknown> }),
query: this.#queries[query]!,
}) as Promise<GraphQLQueryResult<Result>>;
}
}