graphql-operation-store
v0.1.0
Published
Framework-agnostic persisted query and trusted document store for GraphQL
Maintainers
Readme
graphql-operation-store
Framework-agnostic Automatic Persisted Queries (APQ) and trusted document store for GraphQL servers.
Extracts operations from client source at build time, validates incoming requests against a manifest at runtime. Works with any HTTP framework.
Install
npm install graphql-operation-storeHow APQ Works
- Build time: Extract all GraphQL operations from your client codebase into a manifest (hash -> operation mapping).
- Runtime: Clients send only the operation hash instead of the full query string.
- Server: Looks up the hash, finds the operation, and executes it.
Benefits:
- Smaller request payloads
- Prevents arbitrary queries in production (trusted documents)
- Protects against query abuse
Protocol
Client sends:
{
"extensions": {
"persistedQuery": {
"version": 1,
"sha256Hash": "abc123..."
}
}
}Server resolves the hash to the full operation string and executes it. If the hash is unknown in strict mode, it returns:
{
"errors": [{ "message": "PersistedQueryNotFound" }]
}Usage
Strict Mode (Production)
Only allow operations present in the manifest. Unknown hashes are rejected.
import {
createOperationStore,
MemoryStorage,
FileStorage,
} from 'graphql-operation-store';
// Option A: Load from a manifest file
const store = createOperationStore({
storage: new FileStorage('./operation-manifest.json'),
mode: 'strict',
});
// Option B: Load from a manifest object
const store = createOperationStore({
storage: new MemoryStorage(),
mode: 'strict',
});
await store.loadManifest({
version: 1,
operations: [
{ hash: 'abc123', document: 'query GetUser { user { id } }' },
],
});Allow-Unknown Mode (Development)
Allows arbitrary queries and registers them automatically.
const store = createOperationStore({
storage: new MemoryStorage(),
mode: 'allow-unknown',
});Hono / Cloudflare Workers (Fetch API)
import { Hono } from 'hono';
import {
createOperationStore,
FileStorage,
fetchMiddleware,
} from 'graphql-operation-store';
const store = createOperationStore({
storage: new FileStorage('./manifest.json'),
mode: 'strict',
});
const app = new Hono();
app.post('/graphql', async (c) => {
const mw = fetchMiddleware(store);
const result = await mw(c.req.raw);
if (result instanceof Response) {
return result; // Error response (e.g., PersistedQueryNotFound)
}
// result is a new Request with the query filled in
const body = await result.json();
// Pass body.query to your GraphQL executor
});Express
import express from 'express';
import {
createOperationStore,
MemoryStorage,
expressMiddleware,
} from 'graphql-operation-store';
const store = createOperationStore({
storage: new MemoryStorage(),
mode: 'strict',
});
// Load your manifest
await store.loadManifest(require('./manifest.json'));
const app = express();
app.use(express.json());
app.use('/graphql', expressMiddleware(store));Build-Time Extraction
Extract operations from your client source code into a manifest:
import { extractOperations } from 'graphql-operation-store';
await extractOperations({
patterns: ['src/**/*.ts', 'src/**/*.graphql'],
output: './operation-manifest.json',
});This scans for:
gql\...`template literals in.ts/.js` files.graphql/.gqlfiles
And produces a manifest JSON:
{
"version": 1,
"operations": [
{
"hash": "a1b2c3...",
"name": "GetUser",
"document": "query GetUser { user { id name } }"
}
]
}API
createOperationStore(opts: StoreOptions): OperationStore
Creates a new operation store.
opts.storage- AStorageimplementation (MemoryStorage,FileStorage, or custom)opts.mode-'strict'rejects unknown hashes;'allow-unknown'accepts arbitrary queries
OperationStore.loadManifest(manifest: OperationManifest): Promise<void>
Loads operations from a manifest object into storage.
OperationStore.resolve(hashOrQuery: string): Promise<string | null>
Resolves a hash to an operation string. In allow-unknown mode, also accepts raw query strings.
MemoryStorage
In-process Map-based storage.
FileStorage(manifestPath: string)
Lazy-loads a JSON manifest file on first access.
fetchMiddleware(store: OperationStore)
Returns a (req: Request) => Promise<Request | Response> handler for Web Standards environments.
expressMiddleware(store: OperationStore)
Returns Express/Connect middleware.
extractOperations(opts: ExtractOptions): Promise<OperationManifest>
Scans source files and produces an operation manifest.
License
MIT
