npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@kattebak/graphql-sdk-emitter

v1.2.0

Published

Generate a typed TypeScript SDK from a GraphQL SDL with pluggable auth (SigV4, Cognito bearer, API key)

Readme

@kattebak/graphql-sdk-emitter

Generate a typed TypeScript SDK from a GraphQL SDL.

  • One typed function per operation. No query strings in your application code.
  • Pluggable auth providers: SigV4 (AppSync IAM), Cognito bearer, API key. Bring your own.
  • Cursor-pagination helpers as async iterators.
  • LLM-friendly manifest.json describing every operation.
  • Optional smart filter-object builder for nested input types.
  • Framework-agnostic. No React. No global singletons.

Built on top of graphql-codegen (typescript, typescript-operations, typescript-graphql-request) and graphql-request.

Install

npm install --save-dev @kattebak/graphql-sdk-emitter
npm install graphql graphql-request

graphql is a peer dependency. aws4fetch ships in this package and is only loaded when you import SigV4Auth.

Quick start

Given a schema.graphql and a folder of .graphql operations:

npx graphql-sdk-emitter \
	--schema ./schema.graphql \
	--output ./src/generated \
	--operations 'src/operations/*.graphql'

This writes:

src/generated/
	types.ts        # GraphQL types as TypeScript
	sdk.ts          # getSdk(client) with one method per operation
	filters.ts      # buildXxxFilter helpers (optional, on by default)
	manifest.json   # machine-readable operation index
	index.ts        # re-exports everything

In your application:

import { GraphQLClient } from "graphql-request";
import { ApiKeyAuth } from "@kattebak/graphql-sdk-emitter";
import { getSdk } from "./generated";

const auth = new ApiKeyAuth({ apiKey: process.env.API_KEY! });
const client = new GraphQLClient(url, { fetch: auth.wrap(fetch) });
const sdk = getSdk(client);

const r = await sdk.SearchBooks({ query: "tolkien", first: 20 });

Programmatic codegen

import { generateSdk } from "@kattebak/graphql-sdk-emitter";

await generateSdk({
	schema: "./schema.graphql",
	output: "./src/generated",
	operations: "./src/operations/*.graphql", // optional
	emitFilterBuilder: true,                  // default true
	emitManifest: true,                       // default true
});

If you skip operations, the emitter still produces types.ts and manifest.json so you have typed shapes and a discoverable operation index, but no getSdk() runtime.

Auth providers

All three providers implement the same AuthProvider interface:

interface AuthProvider {
	wrap(fetch: FetchFn): FetchFn;
}

You hand the wrapped fetch to GraphQLClient. Implement your own provider by writing one method.

SigV4 (AppSync with IAM)

import { SigV4Auth } from "@kattebak/graphql-sdk-emitter";

const auth = new SigV4Auth({
	credentials: { accessKeyId, secretAccessKey, sessionToken },
	region: "us-east-1",
	service: "appsync", // default
});
const client = new GraphQLClient(url, { fetch: auth.wrap(fetch) });

credentials accepts a () => Credentials | Promise<Credentials> provider for refresh.

Cognito bearer

import { CognitoBearerAuth } from "@kattebak/graphql-sdk-emitter";

const auth = new CognitoBearerAuth({
	token: async () => session.getIdToken().getJwtToken(),
});

API key

import { ApiKeyAuth } from "@kattebak/graphql-sdk-emitter";

const auth = new ApiKeyAuth({ apiKey: process.env.API_KEY! });
// header defaults to x-api-key; override with headerName.

Custom

import type { AuthProvider, FetchFn } from "@kattebak/graphql-sdk-emitter";

class MyAuth implements AuthProvider {
	wrap(fetch: FetchFn): FetchFn {
		return async (input, init) => {
			const headers = new Headers(init?.headers);
			headers.set("x-tenant", "acme");
			return fetch(input, { ...init, headers });
		};
	}
}

Pagination

Two helpers walk Relay-style cursored connections. Pick by what you need per page.

paginatePages — yields the full operation result per page. Types infer from the operation; no generics required.

import { paginatePages } from "@kattebak/graphql-sdk-emitter";

for await (const page of paginatePages(sdk.SearchBooks, { query: "tolkien" }, { pageSize: 50 })) {
	console.log(page.searchBooks.totalCount);
	for (const edge of page.searchBooks.edges) {
		console.log(edge.node.bookId, edge.node.title);
	}
}

paginate / collect — yield a flat array of nodes per page, useful when you only need the nodes. Requires explicit TNode to type the result.

import { paginate, collect } from "@kattebak/graphql-sdk-emitter";

type Book = { bookId: string; title: string };

for await (const nodes of paginate<{ query: string }, unknown, Book>(
	sdk.SearchBooks,
	{ query: "tolkien" },
)) {
	for (const node of nodes) console.log(node.title);
}

const all = await collect<{ query: string }, unknown, Book>(sdk.SearchBooks, { query: "tolkien" });

All three auto-detect the connection inside the response (first object with a pageInfo field). For deeply nested or ambiguous responses pass connectionPath: ["data", "wrapper", "results"]. They stop when hasNextPage is false, when endCursor does not advance, or when maxPages is reached.

Manifest

The emitter writes a manifest.json next to your generated code:

{
	"version": 1,
	"generatedAt": "2026-01-01T00:00:00.000Z",
	"operations": [
		{
			"name": "searchBooks",
			"kind": "query",
			"description": "Search the catalogue by free-text query.",
			"parameters": [
				{ "name": "query", "type": "String", "required": false },
				{ "name": "filter", "type": "BookFilter", "required": false, "description": "Structured filter." }
			],
			"returns": "BookConnection!"
		}
	]
}

Descriptions come from SDL """...""" doc comments. Use this as an LLM-friendly entry point or to drive ad-hoc tooling.

Filter builder

For input types whose name matches Filter, Where, or Condition (or that contain and/or/not combinators), the emitter writes a typed identity helper in filters.ts:

import { buildBookFilter } from "./generated/filters";

const filter = buildBookFilter({
	or: [
		{ title: { contains: "tolkien" } },
		{ author: { contains: "le guin" } },
	],
});

The helper exists to give you autocomplete and type-checking on nested filter shapes without hand-typing the input type.

React + react-query

This package is framework-agnostic. To pair with @tanstack/react-query, write your own thin wrapper:

import { useQuery } from "@tanstack/react-query";

export function useSearchBooks(args: SearchBooksQueryVariables) {
	return useQuery({
		queryKey: ["searchBooks", args],
		queryFn: () => sdk.SearchBooks(args),
	});
}

CLI

graphql-sdk-emitter --schema <path> --output <dir> [options]

  -s, --schema       Path to GraphQL SDL file (required)
  -o, --output       Output directory (required)
  -d, --operations   Path or glob to .graphql operation documents
      --no-filters   Skip filter builder emission
      --no-manifest  Skip operations manifest emission
  -h, --help         Show help

License

MIT