UNPKG

@settlemint/sdk-thegraph

Version:

TheGraph integration module for SettleMint SDK, enabling querying and indexing of blockchain data through subgraphs

1 lines • 27.3 kB
{"version":3,"file":"thegraph.cjs","names":["document: DocumentNode | RequestDocument","target: unknown","source: unknown","result: Record<string, unknown>","document: DocumentNode","variables?: Variables","fetchAllFields?: Set<string>","fields: ListFieldWithFetchAllDirective[]","pathStack: string[]","firstValue: number | undefined","skipValue: number | undefined","otherArgs: ArgumentNode[]","Kind","targetField: ListFieldWithFetchAllDirective","skip: number","first: number","newArgs: ArgumentNode[]","listFields: ListFieldWithFetchAllDirective[]","variables: Variables | undefined","filtered: Variables","theGraphClient: Pick<GraphQLClient, \"request\">","field: ListFieldWithFetchAllDirective","requestHeaders?: HeadersInit","results: unknown[]","documentOrOptions: TadaDocumentNode<TResult, TVariables> | RequestDocument | RequestOptions<TVariables, TResult>","variablesRaw?: Omit<TVariables, \"skip\" | \"first\">","requestHeadersRaw?: HeadersInit","document: TadaDocumentNode<TResult, TVariables> | RequestDocument","variables: Omit<TVariables, \"skip\" | \"first\">","requestHeaders: HeadersInit | undefined","args: unknown","UrlOrPathSchema","options: ClientOptions","instance","clientOptions?: RequestConfig","graphql","GraphQLClient"],"sources":["../src/utils/pagination.ts","../src/thegraph.ts"],"sourcesContent":["import { sortBy } from \"es-toolkit\";\nimport { get, isArray, isEmpty, set } from \"es-toolkit/compat\";\nimport type { TadaDocumentNode } from \"gql.tada\";\nimport { type ArgumentNode, type DocumentNode, Kind, parse, visit } from \"graphql\";\nimport type { GraphQLClient, RequestDocument, RequestOptions, Variables } from \"graphql-request\";\n\n// Constants for TheGraph limits\nconst THE_GRAPH_LIMIT = 500;\nconst FIRST_ARG = \"first\";\nconst SKIP_ARG = \"skip\";\nconst FETCH_ALL_DIRECTIVE = \"fetchAll\";\n\ninterface ListFieldWithFetchAllDirective {\n path: string[];\n fieldName: string;\n firstValue?: number;\n skipValue?: number;\n otherArgs: ArgumentNode[];\n}\n\n/**\n * Detects and strips @fetchAll directives from a GraphQL document\n *\n * @param {DocumentNode} document - The GraphQL document to process\n * @returns {Object} Processed document and list of fields with @fetchAll\n *\n * @remarks\n * This function:\n * - Identifies fields decorated with @fetchAll directive\n * - Removes the directive from the AST (The Graph doesn't recognize it)\n * - Returns both the cleaned document and a list of fields to auto-paginate\n */\nfunction stripFetchAllDirective(document: DocumentNode | RequestDocument): {\n document: DocumentNode;\n fetchAllFields: Set<string>;\n} {\n const fetchAllFields = new Set<string>();\n const documentNode = typeof document === \"string\" ? parse(document) : document;\n const strippedDocument = visit(documentNode, {\n Field(node) {\n // Check if this field has the @fetchAll directive\n if (node.directives && node.directives.length > 0) {\n const hasFetchAll = node.directives.some((dir) => dir.name.value === FETCH_ALL_DIRECTIVE);\n\n if (hasFetchAll) {\n const fieldIdentifier = node.alias?.value || node.name.value;\n fetchAllFields.add(fieldIdentifier);\n\n // Return a new node without the @fetchAll directive\n return {\n ...node,\n directives: node.directives.filter((dir) => dir.name.value !== FETCH_ALL_DIRECTIVE),\n };\n }\n }\n\n return node;\n },\n });\n\n return {\n document: strippedDocument,\n fetchAllFields,\n };\n}\n\n/**\n * Custom merge function for deep object merging with special handling for lists\n *\n * @param {unknown} target - The target object or value to merge into\n * @param {unknown} source - The source object or value to merge from\n * @returns {unknown} Merged result with preservation of arrays and specific merge logic\n *\n * @remarks\n * Key behaviors:\n * - Preserves existing arrays without merging\n * - Handles null and undefined values\n * - Performs deep merge for nested objects\n * - Prioritizes source values for primitives\n *\n */\nfunction customMerge(target: unknown, source: unknown): unknown {\n if (source == null) return target;\n if (target == null) return source;\n\n // If source is an array, return it, don't merge arrays\n if (isArray(source)) {\n return source;\n }\n\n if (typeof target !== \"object\" || typeof source !== \"object\") {\n return source;\n }\n\n // Manually merge objects to ensure arrays are preserved\n const targetObj = target as Record<string, unknown>;\n const sourceObj = source as Record<string, unknown>;\n const result: Record<string, unknown> = { ...targetObj };\n\n for (const key in sourceObj) {\n if (Object.hasOwn(sourceObj, key)) {\n result[key] = key in result ? customMerge(result[key], sourceObj[key]) : sourceObj[key];\n }\n }\n\n return result;\n}\n\n// Extract all fields that have @fetchAll directive\nfunction extractFetchAllFields(\n document: DocumentNode,\n variables?: Variables,\n fetchAllFields?: Set<string>,\n): ListFieldWithFetchAllDirective[] {\n const fields: ListFieldWithFetchAllDirective[] = [];\n const pathStack: string[] = [];\n\n visit(document, {\n Field: {\n enter: (node) => {\n const fieldIdentifier = node.alias?.value || node.name.value;\n pathStack.push(fieldIdentifier);\n\n // Skip meta fields\n if (node.name.value.startsWith(\"__\")) {\n return;\n }\n\n // Check if this field has pagination arguments (first or skip)\n let firstValue: number | undefined;\n let skipValue: number | undefined;\n const otherArgs: ArgumentNode[] = [];\n\n if (node.arguments) {\n for (const arg of node.arguments) {\n if (arg.name.value === FIRST_ARG) {\n if (arg.value.kind === Kind.INT) {\n firstValue = Number.parseInt(arg.value.value);\n } else if (arg.value.kind === Kind.VARIABLE && variables) {\n const varName = arg.value.name.value;\n const varValue = (variables as Record<string, unknown>)[varName];\n firstValue = typeof varValue === \"number\" ? varValue : undefined;\n }\n } else if (arg.name.value === SKIP_ARG) {\n if (arg.value.kind === Kind.INT) {\n skipValue = Number.parseInt(arg.value.value);\n } else if (arg.value.kind === Kind.VARIABLE && variables) {\n const varName = arg.value.name.value;\n const varValue = (variables as Record<string, unknown>)[varName];\n skipValue = typeof varValue === \"number\" ? varValue : undefined;\n }\n } else {\n otherArgs.push(arg);\n }\n }\n }\n\n // Check if this field has @fetchAll directive\n const fieldIdentifierForDirective = node.alias?.value || node.name.value;\n const hasFetchAllDirective = fetchAllFields?.has(fieldIdentifierForDirective);\n\n if (hasFetchAllDirective) {\n // Do not allow nesting @fetchAll fields\n const parentFetchAllField = fields.find((field) => pathStack.join(\",\").startsWith(field.path.join(\",\")));\n if (parentFetchAllField) {\n throw new Error(\n `Nesting of @fetchAll directive is not supported: ${pathStack.join(\".\")} is a child of ${parentFetchAllField.path.join(\".\")}`,\n );\n }\n fields.push({\n path: [...pathStack],\n fieldName: node.name.value,\n firstValue: firstValue ?? THE_GRAPH_LIMIT,\n skipValue: skipValue ?? 0,\n otherArgs,\n });\n }\n },\n leave: () => {\n pathStack.pop();\n },\n },\n });\n\n return fields;\n}\n\n// Create a query for a single field with specific pagination\nfunction createSingleFieldQuery(\n document: DocumentNode,\n targetField: ListFieldWithFetchAllDirective,\n skip: number,\n first: number,\n): DocumentNode {\n const targetPath = [...targetField.path];\n const pathStack: string[] = [];\n\n return visit(document, {\n Field: {\n enter: (node) => {\n const fieldIdentifier = node.alias?.value || node.name.value;\n pathStack.push(fieldIdentifier);\n\n // Check if we're on the path to target field\n const onPath = pathStack.every((segment, i) => i >= targetPath.length || segment === targetPath[i]);\n\n if (!onPath) {\n pathStack.pop();\n return null; // Remove fields not on path\n }\n\n // If this is our target field, update pagination\n const isTarget =\n pathStack.length === targetPath.length && pathStack.every((segment, i) => segment === targetPath[i]);\n\n if (isTarget) {\n const newArgs: ArgumentNode[] = [...targetField.otherArgs];\n\n // Add pagination arguments\n newArgs.push(\n {\n kind: Kind.ARGUMENT,\n name: { kind: Kind.NAME, value: FIRST_ARG },\n value: { kind: Kind.INT, value: first.toString() },\n },\n {\n kind: Kind.ARGUMENT,\n name: { kind: Kind.NAME, value: SKIP_ARG },\n value: { kind: Kind.INT, value: skip.toString() },\n },\n );\n\n return { ...node, arguments: newArgs };\n }\n\n return undefined;\n },\n leave: () => {\n pathStack.pop();\n },\n },\n });\n}\n\n// Create query without list fields\nfunction createNonListQuery(document: DocumentNode, listFields: ListFieldWithFetchAllDirective[]): DocumentNode | null {\n let hasFields = false;\n const pathStack: string[] = [];\n\n const filtered = visit(document, {\n Field: {\n enter: (node) => {\n const fieldIdentifier = node.alias?.value || node.name.value;\n pathStack.push(fieldIdentifier);\n\n // Check if this field is a list field\n const isList = listFields.some(\n (field) =>\n field.path.length === pathStack.length && field.path.every((segment, i) => segment === pathStack[i]),\n );\n\n if (isList) {\n pathStack.pop();\n return null;\n }\n\n hasFields = true;\n return undefined;\n },\n leave: () => {\n pathStack.pop();\n },\n },\n });\n\n return hasFields ? filtered : null;\n}\n\n// Filter variables to only include used ones\nfunction filterVariables(variables: Variables | undefined, document: DocumentNode): Variables | undefined {\n if (!variables) return undefined;\n\n const usedVariables = new Set<string>();\n\n visit(document, {\n Variable: (node) => {\n usedVariables.add(node.name.value);\n },\n });\n\n const filtered: Variables = {};\n const varsObj = variables as Record<string, unknown>;\n for (const key of usedVariables) {\n if (key in varsObj) {\n (filtered as Record<string, unknown>)[key] = varsObj[key];\n }\n }\n\n return isEmpty(filtered) ? undefined : filtered;\n}\n\n/**\n * Creates a TheGraph client that supports pagination for list fields\n *\n * @param theGraphClient - The GraphQL client to use for requests\n * @returns A TheGraph client that supports pagination for list fields\n * @internal Used internally by createTheGraphClient\n */\nexport function createTheGraphClientWithPagination(theGraphClient: Pick<GraphQLClient, \"request\">) {\n // Execute pagination for a list field\n async function executeListFieldPagination(\n document: DocumentNode,\n variables: Variables | undefined,\n field: ListFieldWithFetchAllDirective,\n requestHeaders?: HeadersInit,\n ): Promise<unknown[]> {\n const results: unknown[] = [];\n let currentSkip = field.skipValue || 0;\n let hasMore = true;\n\n // For fields with pagination arguments, always attempt to fetch data\n // and continue if we get a full page (indicating more data might exist)\n const batchSize = Math.min(field.firstValue || THE_GRAPH_LIMIT, THE_GRAPH_LIMIT);\n\n while (hasMore) {\n const query = createSingleFieldQuery(document, field, currentSkip, batchSize);\n const existingVariables = filterVariables(variables, query) ?? {};\n const response = await theGraphClient.request(\n query,\n {\n ...existingVariables,\n first: batchSize,\n skip: currentSkip,\n },\n requestHeaders,\n );\n\n // Use array path format for es-toolkit's get function\n const data = get(response, field.path) ?? get(response, field.fieldName);\n\n const parentPath = field.path.slice(0, -1);\n const parentData = get(response, parentPath);\n if (isArray(parentData) && parentData.length > 0) {\n throw new Error(\n `Response is an array, but expected a single object for field ${parentPath.join(\".\")}. The @fetchAll directive is not supported inside a query that returns a list of items.`,\n );\n }\n\n if (isArray(data) && data.length > 0) {\n results.push(...data);\n\n // With @fetchAll, continue if we got a full batch\n hasMore = data.length === batchSize;\n } else {\n hasMore = false;\n }\n\n currentSkip += batchSize;\n }\n\n return results;\n }\n\n return {\n async query<TResult, TVariables extends Variables>(\n documentOrOptions: TadaDocumentNode<TResult, TVariables> | RequestDocument | RequestOptions<TVariables, TResult>,\n variablesRaw?: Omit<TVariables, \"skip\" | \"first\">,\n requestHeadersRaw?: HeadersInit,\n ): Promise<TResult> {\n let document: TadaDocumentNode<TResult, TVariables> | RequestDocument;\n let variables: Omit<TVariables, \"skip\" | \"first\">;\n let requestHeaders: HeadersInit | undefined;\n\n if (isRequestOptions(documentOrOptions)) {\n document = documentOrOptions.document;\n variables = (documentOrOptions.variables ?? {}) as TVariables;\n requestHeaders = documentOrOptions.requestHeaders;\n } else {\n document = documentOrOptions;\n variables = variablesRaw ?? ({} as TVariables);\n requestHeaders = requestHeadersRaw;\n }\n\n // First, detect and strip @fetchAll directives\n const { document: processedDocument, fetchAllFields } = stripFetchAllDirective(document);\n\n // Extract all list fields (including those with @fetchAll)\n const listFields = extractFetchAllFields(processedDocument, variables, fetchAllFields);\n\n // If no list fields, execute normally\n if (listFields.length === 0) {\n return theGraphClient.request(processedDocument, variables as Variables, requestHeaders);\n }\n\n // Execute paginated queries for all list fields\n const result: Record<string, unknown> = {};\n\n // Sort fields by depth to handle nested fields correctly\n const sortedFields = sortBy(listFields, [(field) => field.path.length]);\n\n // Process list fields in parallel for better performance\n const fieldDataPromises = sortedFields.map(async (field) => ({\n field,\n data: await executeListFieldPagination(processedDocument, variables, field, requestHeaders),\n }));\n\n const fieldResults = await Promise.all(fieldDataPromises);\n\n // Set results in order\n for (const { field, data } of fieldResults) {\n // Use array path format for es-toolkit's set function\n set(result, field.path, data);\n }\n\n // Execute non-list fields (single entity queries)\n const nonListQuery = createNonListQuery(processedDocument, listFields);\n\n if (nonListQuery) {\n const nonListResult = await theGraphClient.request(\n nonListQuery,\n filterVariables(variables, nonListQuery) ?? {},\n requestHeaders,\n );\n\n // Merge results, preserving list data\n const merged = customMerge(nonListResult, result);\n return merged as TResult;\n }\n\n return result as TResult;\n },\n } as const;\n}\n\nfunction isRequestOptions(args: unknown): args is RequestOptions<Variables, unknown> {\n return typeof args === \"object\" && args !== null && \"document\" in args;\n}\n","import { appendHeaders } from \"@settlemint/sdk-utils/http\";\nimport { ensureServer } from \"@settlemint/sdk-utils/runtime\";\nimport { ApplicationAccessTokenSchema, UrlOrPathSchema, validate } from \"@settlemint/sdk-utils/validation\";\nimport { type AbstractSetupSchema, initGraphQLTada } from \"gql.tada\";\nimport { GraphQLClient } from \"graphql-request\";\nimport { z } from \"zod\";\nimport { createTheGraphClientWithPagination } from \"./utils/pagination.js\";\n\n/**\n * Type definition for GraphQL client configuration options\n */\nexport type RequestConfig = ConstructorParameters<typeof GraphQLClient>[1];\n\n/**\n * Schema for validating client options for the TheGraph client.\n */\nexport const ClientOptionsSchema = z.object({\n instances: z.array(UrlOrPathSchema),\n accessToken: ApplicationAccessTokenSchema.optional(),\n subgraphName: z.string(),\n cache: z.enum([\"default\", \"force-cache\", \"no-cache\", \"no-store\", \"only-if-cached\", \"reload\"]).optional(),\n});\n\n/**\n * Type definition for client options derived from the ClientOptionsSchema\n */\nexport type ClientOptions = z.infer<typeof ClientOptionsSchema>;\n\n/**\n * Constructs the full URL for TheGraph GraphQL API based on the provided options\n *\n * @param options - The client options for configuring TheGraph client\n * @returns The complete GraphQL API URL as a string\n * @throws Will throw an error if no matching instance is found for the specified subgraph\n */\nfunction getFullUrl(options: ClientOptions): string {\n const instance = options.instances.find((instance) => instance.endsWith(`/${options.subgraphName}`));\n if (!instance) {\n throw new Error(`Instance for subgraph ${options.subgraphName} not found`);\n }\n return new URL(instance).toString();\n}\n\n/**\n * Creates a TheGraph GraphQL client with proper type safety using gql.tada\n *\n * @param options - Configuration options for the client including instance URLs,\n * access token and subgraph name\n * @param clientOptions - Optional GraphQL client configuration options\n * @returns An object containing:\n * - client: The configured GraphQL client instance\n * - graphql: The initialized gql.tada function for type-safe queries\n * @throws Will throw an error if the options fail validation against ClientOptionsSchema\n * @example\n * import { createTheGraphClient } from '@settlemint/sdk-thegraph';\n * import type { introspection } from '@schemas/the-graph-env-kits';\n * import { createLogger, requestLogger } from '@settlemint/sdk-utils/logging';\n *\n * const logger = createLogger();\n *\n * const { client, graphql } = createTheGraphClient<{\n * introspection: introspection;\n * disableMasking: true;\n * scalars: {\n * Bytes: string;\n * Int8: string;\n * BigInt: string;\n * BigDecimal: string;\n * Timestamp: string;\n * };\n * }>({\n * instances: JSON.parse(process.env.SETTLEMINT_THEGRAPH_SUBGRAPHS_ENDPOINTS || '[]'),\n * accessToken: process.env.SETTLEMINT_ACCESS_TOKEN,\n * subgraphName: 'kits'\n * }, {\n * fetch: requestLogger(logger, \"the-graph-kits\", fetch) as typeof fetch,\n * });\n *\n * // Making GraphQL queries\n * const query = graphql(`\n * query SearchAssets {\n * assets @fetchAll {\n * id\n * name\n * symbol\n * }\n * }\n * `);\n *\n * const result = await client.request(query);\n */\nexport function createTheGraphClient<const Setup extends AbstractSetupSchema>(\n options: ClientOptions,\n clientOptions?: RequestConfig,\n): {\n client: GraphQLClient;\n graphql: initGraphQLTada<Setup>;\n} {\n ensureServer();\n const validatedOptions = validate(ClientOptionsSchema, options);\n const graphql = initGraphQLTada<Setup>();\n const fullUrl = getFullUrl(validatedOptions);\n\n const client = new GraphQLClient(fullUrl, {\n ...clientOptions,\n headers: appendHeaders(clientOptions?.headers, { \"x-auth-token\": validatedOptions.accessToken }),\n });\n const originalRequest = client.request.bind(client);\n const paginatedClient = createTheGraphClientWithPagination({\n request: originalRequest,\n });\n client.request = paginatedClient.query;\n return {\n client,\n graphql,\n };\n}\n\nexport type { FragmentOf, ResultOf, VariablesOf } from \"gql.tada\";\nexport { readFragment } from \"gql.tada\";\nexport { createTheGraphClientWithPagination } from \"./utils/pagination.js\";\n"],"mappings":"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"}