On this page

@envelop/response-cache

Changelog for @envelop/response-cache: every release with its changes and the pull requests behind them.

10.0.0

Major Changes

  • #4574 79b0e8b Thanks @egoodwinx! - ### Breaking Changes

    • Node: minimum supported version is now Node 22. Node 18 and 20 are no longer supported. Future releases will only support Node >=22.
    • GraphQL: minimum supported version is now GraphQL 16. GraphQL 14 and 15 are no longer supported.
    • Request body parsing: Yoga now limits request bodies to 25,000,000 bytes by default. Enforcing this limit streams the body through a byte counter, making POST body parsing asynchronous even for an in-memory body. As a result, yoga.fetch() can return a Promise where it previously returned a synchronous Response, even when all resolvers and plugins are synchronous.

    Migration

    • If you’re on Node 18/20, upgrade to Node 22 or later before upgrading this package.
    • If you’re on graphql 14/15, upgrade to graphql 16 or 17 first.
    • Await yoga.fetch() and response body parsing instead of relying on synchronous results. Set maxRequestBodySize: false in createYoga to disable the body-size limit and preserve synchronous parsing for in-memory bodies, but only if you enforce an appropriate request-body limit elsewhere.
  • #4623 be89d05 Thanks @ardatan! - ### Dependencies

    • Bump @graphql-tools/utils to ^13.1.1, @graphql-tools/schema to ^11.0.0, and @graphql-tools/executor to ^4.1.2.

    Incremental delivery

    Yoga maps the GraphQL HTTP Accept header through INCREMENTAL_DELIVERY_SPECS from @graphql-tools/utils onto executor incrementalSpec. multipart/mixed;incrementalSpec=v0.2 runs the v0.2 payload format and echoes that spec on Content-Type. multipart/mixed;deferSpec=20220824 or bare multipart/mixed stays on v0.1. An unsupported incremental spec yields 406.

    A later incremental spec is a graphql-tools table row plus an executor publisher. Yoga, Hive Gateway, and HTTP executors pick it up by bumping @graphql-tools/utils / @graphql-tools/executor.

    Breaking Changes

    • createGraphQLError is removed. Use new GraphQLError(message, options) from graphql. To attach Yoga’s experimental schema coordinate, use withSchemaCoordinate(error, coordinate) and read with getSchemaCoordinate from @graphql-tools/utils.
    • mapMaybePromise is removed (was exported from Yoga / @envelop/core). Use handleMaybePromise from @whatwg-node/promise-helpers.
    • Yoga no longer re-exports helpers that already live upstream:
      • getSchemaCoordinate -> @graphql-tools/utils
      • mergeSchemas -> @graphql-tools/schema
      • DisposableSymbols -> @whatwg-node/server
      • mapAsyncIterator / isPromise / fakePromise / handleMaybePromise / MaybePromise -> @whatwg-node/promise-helpers
    • @envelop/core utils no longer re-exports mapAsyncIterator or isPromise. Import from @whatwg-node/promise-helpers.
    • Use asGetArgumentValuesVariables / coerceGetVariableValuesResult from @graphql-tools/utils for GraphQL 16/17 VariableValues compatibility.

    Migration

    import { GraphQLError } from 'graphql'
    import { withSchemaCoordinate } from 'graphql-yoga'
    import { mergeSchemas } from '@graphql-tools/schema'
    import { getSchemaCoordinate } from '@graphql-tools/utils'
    import { handleMaybePromise, isPromise, type MaybePromise } from '@whatwg-node/promise-helpers'
    import { DisposableSymbols } from '@whatwg-node/server'
    
    throw withSchemaCoordinate(new GraphQLError('not found'), 'Query.user')

Minor Changes

  • #4575 862447a Thanks @egoodwinx! - Use @graphql-hive/logger and add correlated, per-request logging (closes #4048)

    Every request now gets its own logger, available as context.log (and serverContext.log in plugin hooks), tagged with a requestId. Everything logged while handling a request can be correlated by that id.

    The request id is taken from the host integration if it already assigned one (e.g. Fastify’s request.id), otherwise from the incoming x-request-id header, otherwise generated. It is also sent back in the x-request-id response header. Configure it with the new requestId option:

    createYoga({
      requestId: {
        // don't trust the incoming header, recommended when clients can reach the server directly
        trustHeader: false,
        headerName: 'x-correlation-id',
        generateRequestId: () => myId()
      }
    })

    Pass requestId: false to disable it.

    At the info level, a single “Request processed” line is logged per request with the method, path, operation name and type, response status, error count and duration. At the debug level, more details about request processing are logged.

    Masked errors are now logged with the request’s logger, so they can be traced back to the request that caused them. Custom maskError functions receive the request’s context as an optional fourth argument.

    The @envelop/newrelic, @envelop/auth0, @envelop/resource-limitations, @envelop/statsd, @envelop/graphql-jit, @envelop/response-cache and @envelop/response-cache-cloudflare-kv plugins accept a new log option for their own messages, instead of always writing to the console.

    @envelop/response-cache’s shouldCacheResult now also receives the GraphQL context.

    Breaking Changes

    • The @graphql-yoga/logger package has been removed. graphql-yoga re-exports Logger, MemoryLogWriter and LogLevel from @graphql-hive/logger instead.
    • createLogger and the YogaLogger type are no longer exported. Use new Logger(options) instead.
    • The logging option now takes boolean | Logger | LogLevel, where Logger is the one from @graphql-hive/logger.
    • yoga.logger has been renamed to yoga.log.
    • The logger option of useGraphiQL and useHealthCheck has been removed. They now log through the request’s logger.
    • @graphql-yoga/nestjs now logs through Nest’s Logger by default instead of not logging at all. Pass logging: false to keep the previous behaviour. logging: true on Fastify no longer logs through Fastify’s logger, pass it explicitly instead (see below).
    • @envelop/apollo-federation, @envelop/auth0, @envelop/graphql-jit, @envelop/newrelic, @envelop/resource-limitations, @envelop/response-cache, @envelop/response-cache-cloudflare-kv and @envelop/statsd now have a peer dependency on @graphql-hive/logger that you must install.
    • @envelop/apollo-federation’s logger option now expects a Logger from @graphql-hive/logger and defaults to new Logger() instead of console.

    Migration

    Create loggers with Logger:

    - import { createLogger } from 'graphql-yoga';
    + import { Logger } from 'graphql-yoga';
    
      createYoga({
    -   logging: createLogger('debug'),
    +   logging: new Logger({ level: 'debug' }),
      });

    Use log instead of logger on the Yoga instance:

      const plugin = {
        onYogaInit({ yoga }) {
    -     yoga.logger.info('ready');
    +     yoga.log.info('ready');
        },
      };

    Prefer the request-scoped logger inside resolvers and plugin hooks so the logs carry the request id:

    const resolvers = {
      Query: {
        hello: (_, __, context) => {
          context.log.debug('resolving hello')
          return 'world'
        }
      }
    }

    If you use any of the @envelop/* plugins listed above, install the logger:

    npm i @graphql-hive/logger

    If you depended on @graphql-yoga/logger directly, switch to @graphql-hive/logger:

    - import { Logger } from '@graphql-yoga/logger';
    + import { Logger } from '@graphql-hive/logger';

    To keep logging through Fastify’s logger in @graphql-yoga/nestjs:

    import { Logger } from 'graphql-yoga'
    import { PinoLogWriter } from '@graphql-hive/logger/writers/pino'
    
    // in your yoga driver options
    logging: new Logger({ writers: [new PinoLogWriter(app.log)] })

Patch Changes

9.3.4

Patch Changes

  • #4602 9fde867 Thanks @peterklingelhofer! - Walk each array in a result only once when removing the plugin’s metadata fields. Arrays were also walked a second time as objects, which doubled the work at every level of nesting, so deeply nested results (for example a large JSON tree) took exponentially longer to process than needed. This ran on every response the plugin handled, including ones with a TTL of 0 that are never stored.

9.3.3

Patch Changes

9.3.2

Patch Changes

9.3.1

Patch Changes

9.3.0

Minor Changes

  • #4571 ab4aeaa Thanks @egoodwinx! - Fix the in-memory cache memory leak in purgeResponse and LRUCache dispose issue (closes #4409, closes #4544)

9.2.0

Minor Changes

  • #4545 94ebe5b Thanks @egoodwinx! - Update to support graphql-js 17

    Bump package versions, fix expected typing, and update compatability with subscribe.

Patch Changes

  • Updated dependencies [94ebe5b]:
    • @envelop/core@5.6.0

9.1.1

Patch Changes

  • Updated dependencies [0bfde27]:
    • @envelop/core@5.5.1

9.1.0

Patch Changes

9.0.0

Patch Changes

  • Updated dependencies [0434fbd]:
    • @envelop/core@5.4.0

8.1.0

Minor Changes

  • #2258 35539a7 Thanks @EmrysMyrddin! - Deprecate ttlPerType in favor of ttlPerSchemaCoordinate, for a more streamlined API

    Migration instructions

    If you where using ttlPerType, you can merge the object into the ttlPerSchemaCoordinate, the syntax doesn’t change.

    useResponseCache({
      session: null,
    - ttlPerType: {
    -   User: 10_000,
    -   Profile: 600_000,
    - },
      ttlPerSchemaCoordinate: {
        'Query.me': 0
    +    User: 10_000,
    +    Profile: 600_000,
      }
    })

8.0.2

Patch Changes

8.0.1

Patch Changes

  • #2611 8dd5bda Thanks @EmrysMyrddin! - Add a withState override to ease the typing of plugins whith the same state for all scopes.

  • Updated dependencies [8dd5bda]:

    • @envelop/core@5.3.1

8.0.0

Patch Changes

  • Updated dependencies [3ebaa3b]:
    • @envelop/core@5.3.0

7.1.3

Patch Changes

7.1.2

Patch Changes

7.1.1

Patch Changes

7.1.0

Patch Changes

7.0.1

Patch Changes

  • Updated dependencies [5b6a166]:
    • @envelop/core@5.1.1

7.0.0

Patch Changes

6.3.0

Minor Changes

6.2.5

Patch Changes

6.2.4

Patch Changes

  • c1720a8 Thanks @n1ru4l! - Fix handling of primitive list values that was introduced in the last release.

6.2.3

Patch Changes

6.2.2

Patch Changes

  • #2309 4fd5917 Thanks @n1ru4l! - Strip __responseCacheId and __responseCacheTypeName from incremental delivery execution result.

6.2.1

Patch Changes

  • #2266 389d5f6 Thanks @EmrysMyrddin! - The plugin now try to reduce the size of the resulting query by not adding a __typename aliased selection if __typename is already selected.

6.2.0

Minor Changes

  • #2238 430ee7d Thanks @ardatan! - Accept a factory function to cache that takes the context and returns the cache implementation

6.1.2

Patch Changes

  • 4a1e50b Thanks @EmrysMyrddin! - Do not cache response with a TTL equal to 0, whatever API is used to define the TTL

6.1.1

Patch Changes

  • #2090 09a4bc1 Thanks @klippx! - Fix TTL being NaN when using @cacheControl without maxAge argument.

6.1.0

Minor Changes

6.0.1

Patch Changes

6.0.0

Major Changes

  • #1977 a4343bee Thanks @EmrysMyrddin! - The enable parameter now allows to entirely disable caching. It is checked eagerly and disables all cache related processing.

    Breaking Change:

    Previously, enable was only controlling cache reading. This means that previously, the automatic cache invalidation was still working even with enable returning false, which is no longer the case. The alternative is to cautiously invalidate data in the related resolvers.

  • Updated dependencies [68e7a2a5, f7ef03c0]:

    • @envelop/core@5.0.0

5.5.0

Minor Changes

  • #1970 b2ce17e2 Thanks @EmrysMyrddin! - Automatically add the entities id to the request document. This change allows the plugin to not require anymore each query to carefuly include all keys of all entities.

5.4.0

Minor Changes

5.3.2

Patch Changes

  • c9e493b8 Thanks @ardatan! - Ignore subscriptions in response caching

  • Updated dependencies [dee6b8d2]:

    • @envelop/core@4.0.3

5.3.1

Patch Changes

5.3.0

Minor Changes

5.2.0

Minor Changes

Patch Changes

5.1.0

Minor Changes

  • #1603 ea907c60 Thanks @ardatan! - Support for directive @cacheControl(maxAge: Int) on FIELD_DEFINITION | OBJECT | INTERFACE | UNION

Patch Changes

5.0.1

Patch Changes

  • #1873 914d78c3 Thanks @ardatan! - Do not revisit cached parser result which adds extra __typename properties in the execution result

5.0.0

Major Changes

Patch Changes

4.0.8

Patch Changes

4.0.7

Patch Changes

4.0.6

Patch Changes

  • #1724 94e39a5d Thanks @ardatan! - - Respect existing extensions in the result
    • Add cacheKey to shouldCacheResult function
  • Updated dependencies [270249cf]:
    • @envelop/core@3.0.5

4.0.5

Patch Changes

4.0.4

Patch Changes

  • Updated dependencies []:
    • @envelop/core@3.0.4

4.0.3

Patch Changes

  • Updated dependencies [6b48ef96]:
    • @envelop/core@3.0.3

4.0.2

Patch Changes

4.0.0

Major Changes

3.2.0

Minor Changes

  • #1499 1f7af02b Thanks @viniciuspalma! - Adding tslib to package dependencies

    Projects that currently are using yarn Berry with PnP or any strict dependency resolver, that requires that all dependencies are specified on package.json otherwise it would endue in an error if not treated correct

    Since https://www.typescriptlang.org/tsconfig#importHelpers is currently being used, tslib should be exported as a dependency to external runners get the proper import.

    Change on each package:

    // package.json
    {
      "dependencies": {
        "tslib": "^2.4.0"
      }
    }
  • Updated dependencies [1f7af02b, ae7bc9a3]:

    • @envelop/core@2.6.0

3.1.0

Minor Changes

3.0.2

Patch Changes

  • 071f946: Fix CommonJS TypeScript resolution with moduleResolution node16 or nodenext
  • Updated dependencies [071f946]
    • @envelop/core@2.4.2

3.0.1

Patch Changes

  • Updated dependencies [787d28a2]
    • @envelop/core@2.4.1

3.0.0

Major Changes

  • 887fc07: BREAKING Require the user to provide a session function by default.

    Previously, using the response cache automatically used a global cache. For security reasons there is no longer a default value for the session config property. If you did not set the session function before and want a global cache that is shared by all users, you need to update your code to the following:

    import { envelop } from '@envelop/core'
    import { useResponseCache } from '@envelop/response-cache'
    
    const getEnveloped = envelop({
      plugins: [
        // ... other plugins ...
        useResponseCache({
          // use global cache for all operations
          session: () => null
        })
      ]
    })

    Otherwise, you should return from your cache function a value that uniquely identifies the viewer.

    import { envelop } from '@envelop/core'
    import { useResponseCache } from '@envelop/response-cache'
    
    const getEnveloped = envelop({
      plugins: [
        // ... other plugins ...
        useResponseCache({
          // return null as a fallback for caching the result globally
          session: context => context.user?.id ?? null
        })
      ]
    })
  • a5d8dcb: Better default document string storage

    Previously non parsed operation document was stored in the context with a symbol to be used “documentString” in the later. But this can be solved with a “WeakMap” so the modification in the context is no longer needed.

    BREAKING CHANGE: Replace getDocumentStringFromContext with getDocumentString

    However, some users might provide document directly to the execution without parsing it via parse. So in that case, we replaced the context parameter with the execution args including document, variableValues and contextValue to the new getDocumentString.

    Now a valid document string should be returned from the new getDocumentString.

    Custom document string caching example.

    const myCache = new WeakMap<DocumentNode, string>()
    
    // Let's say you keep parse results in somewhere else like below
    function parseDocument(document: string): DocumentNode {
      const parsedDocument = parse(document)
      myCache.set(parsedDocument, document)
      return parsedDocument
    }
    
    // Then you can interact with your existing caching solution inside the response cache plugin like below
    useResponseCache({
      getDocumentString(document: DocumentNode): string {
        // You can also add a fallback to `graphql-js`'s print function
        // to let the plugin works
        const possibleDocumentStr = myCache.get(document)
        if (!possibleDocumentStr) {
          console.warn(`Something might be wrong with my cache setup`)
          return print(document)
        }
        return possibleDocumentStr
      }
    })

    Migration from getDocumentStringFromContext.

    So if you use getDocumentStringFromContext like below before;

    function getDocumentStringFromContext(contextValue: any) {
      return contextValue.myDocumentString
    }

    You have to change it to the following;

    import { print } from 'graphql'
    
    function getDocumentString(executionArgs: ExecutionArgs) {
      // We need to fallback to `graphql`'s print to return a value no matter what.
      return executionArgs.contextValue.myDocumentString ?? print(executionArgs.document)
    }

2.4.0

Minor Changes

  • 8bb2738: Support TypeScript module resolution.
  • Updated dependencies [8bb2738]
    • @envelop/core@2.4.0

2.3.3

Patch Changes

  • fbf6155: update package.json repository links to point to the new home
  • Updated dependencies [fbf6155]
    • @envelop/core@2.3.3

2.3.2

Patch Changes

  • Updated dependencies [07d029b]
    • @envelop/core@2.3.2

2.3.1

Patch Changes

  • Updated dependencies [d5c2c9a]
    • @envelop/core@2.3.1

2.3.0

Minor Changes

  • Updated dependencies [af23408]
    • @envelop/core@2.3.0

2.2.0

Minor Changes

  • Updated dependencies [ada7fb0]
  • Updated dependencies [d5115b4]
  • Updated dependencies [d5115b4]
    • @envelop/core@2.2.0

2.1.1

Patch Changes

  • 5400c3f: fix infinite loop while applying schema transforms

2.1.0

Minor Changes

  • Updated dependencies [78b3db2]
  • Updated dependencies [f5eb436]
    • @envelop/core@2.1.0

2.0.0

Patch Changes

  • Updated dependencies [4106e08]
  • Updated dependencies [aac65ef]
  • Updated dependencies [4106e08]
    • @envelop/core@2.0.0

1.0.1

Patch Changes

  • 3dfddb5: Bump graphql-tools/utils to v8.6.1 to address a bug in getArgumentsValues
  • Updated dependencies [3dfddb5]
    • @envelop/core@1.7.1

1.0.0

Patch Changes

  • Updated dependencies [d9cfb7c]
    • @envelop/core@1.7.0

0.6.0

Minor Changes

  • b919b21: Add cross-platform support for platforms that do not have the Node.js crypto module available by using the WebCrypto API. This adds support for deno, cloudflare workers and the browser.

    BREAKING: The BuildResponseCacheKeyFunction function type now returns Promise<string> instead of string.. The function defaultBuildResponseCacheKey now returns a Promise. The UseResponseCacheParameter.buildResponseCacheKey config option must return a Promise. BREAKING: The defaultBuildResponseCacheKey now uses the hash algorithm SHA256 instead of SHA1.

0.5.1

Patch Changes

  • b1a0331: Properly list @envelop/core as a peerDependency in plugins.

    This resolves issues where the bundled envelop plugins published to npm had logic inlined from the @envelop/core package, causing instanceof check of EnvelopError to fail.

  • Updated dependencies [b1a0331]

    • @envelop/core@1.6.1

0.5.0

Minor Changes

  • 090cae4: GraphQL v16 support

0.4.0

Minor Changes

  • 04120de: add support for GraphQL.js 16

0.3.0

Minor Changes

  • 0623cf7: Introspection query operations are no longer cached by default.

    In case you still want to cache query operations you can set the ttlPerSchemaCoordinate parameter to { "Query.__schema": undefined } for caching introspection forever or { "Query.__schema": 100 } for caching introspection for a specific time. We do not recommend caching introspection.

    Query operation execution results that contain errors are no longer cached.

0.2.1

Patch Changes

  • 9688945: Allow to set ttl=0 to disable caching, and use ttlPerType to maintain a whitelist

  • a749ec0: Include operationName for building the cache key hash. Previously, sending the same operation document with a different operationName value could result in the wrong response being served from the cache.

    Use fast-json-stable-stringify for stringifying the variableValues. This will ensure that the cache is hit more often as the variable value serialization is now more stable.

0.2.0

Minor Changes

  • 075fc77: Expose metadata by setting the includeExtensionMetadata option.

    • extension.responseCache.hit - Whether the result was served form the cache or not
    • extension.responseCache.invalidatedEntities - Entities that got invalidated by a mutation operation

    Take a look at the README for mor information and examples.

0.1.0

Minor Changes

  • 823b335: initial release