@graphile/persisted-operations
Version:
Persisted operations (aka persisted queries) support for PostGraphile's server
98 lines (97 loc) • 4.46 kB
TypeScript
import type { IncomingMessage } from "http";
import type { DocumentNode } from "graphql";
/**
* Given a persisted operation hash, return the associated GraphQL operation
* document.
*/
export declare type PersistedOperationGetter = (hash: string) => string;
declare module "postgraphile" {
interface PostGraphileOptions {
/**
* This function will be passed a GraphQL request object (normally `{query:
* string, variables?: any, operationName?: string, extensions?: any}`, but
* in the case of persisted operations it likely won't have a `query`
* property), and must extract the hash to use to identify the persisted
* operation. For Apollo Client, this might be something like:
* `request?.extensions?.persistedQuery?.sha256Hash`; for Relay something
* like: `request?.documentId`.
*/
hashFromPayload?(request: RequestPayload): string;
/**
* We can read persisted operations from a folder (they must be named
* `<hash>.graphql`); this is mostly used for PostGraphile CLI. When used
* in this way, the first request for a hash will read the file
* synchronously, and then the result will be cached such that the
* **synchronous filesystem read** will only impact the first use of that
* hash. We periodically scan the folder for new files, requests for hashes
* that were not present in our last scan of the folder will be rejected to
* mitigate denial of service attacks asking for non-existent hashes.
*/
persistedOperationsDirectory?: string;
/**
* An optional string-string key-value object defining the persisted
* operations, where the keys are the hashes, and the values are the
* operation document strings to use.
*/
persistedOperations?: {
[hash: string]: string;
};
/**
* If your known persisted operations may change over time, or you'd rather
* load them on demand, you may supply this function. Note this function is
* both **synchronous** and **performance critical** so you should use
* caching to improve performance of any follow-up requests for the same
* hash. This function is not suitable for fetching operations from remote
* stores (e.g. S3).
*/
persistedOperationsGetter?: PersistedOperationGetter;
/**
* There are situations where you may want to allow arbitrary operations
* (for example using GraphiQL in development, or allowing an admin to
* make arbitrary requests in production) whilst enforcing Persisted
* Operations for the application and non-admin users. This function
* allows you to determine under which circumstances persisted operations
* may be bypassed.
*
* IMPORTANT: this function must not throw!
*
* @example
*
* ```
* app.use(postgraphile(DATABASE_URL, SCHEMAS, {
* allowUnpersistedOperation(req) {
* return process.env.NODE_ENV === "development" && req.headers.referer.endsWith("/graphiql");
* }
* });
* ```
*/
allowUnpersistedOperation?: boolean | ((request: IncomingMessage, payload: RequestPayload) => boolean);
}
}
/**
* The payload of the request would normally have
* query/operationName/variables/extensions; but in persisted operations it may
* have something else other than `query`. We've typed a few of the more common
* versions, if this doesn't work for you you'll need to cast `payload as any`.
*/
interface RequestPayload {
/** As used by Apollo https://github.com/apollographql/apollo-link-persisted-queries#protocol */
extensions?: {
persistedQuery?: {
sha256Hash?: string;
};
};
/** As used by Relay https://relay.dev/docs/en/persisted-queries#network-layer-changes */
documentId?: string;
/** Non-standard. */
id?: string;
/** The actual query; we're generally expecting a hash via one of the methods above instead */
query?: string | DocumentNode;
/** GraphQL operation variables */
variables?: {
[key: string]: unknown;
};
/** If the document contains more than one operation; the name of the one to execute. */
operationName?: string;
}
export {};