diff --git a/.changeset/chilly-foxes-attack.md b/.changeset/chilly-foxes-attack.md new file mode 100644 index 0000000000000..25c24d8f1e945 --- /dev/null +++ b/.changeset/chilly-foxes-attack.md @@ -0,0 +1,25 @@ +--- +'@graphql-mesh/serve-cli': minor +--- + +Support Hive's experimental persisted documents + +### Using CLI options + +```sh +mesh-serve supergraph [schemaPathOrUrl] --hive-persisted-documents-endpoint "https://cdn.graphql-hive.com/" --hive-persisted-documents-token +``` + +### Using config file + +```ts +import { defineConfig } from '@graphql-mesh/serve-cli' + +export const serveConfig = defineConfig({ + persistedDocuments: { + type: 'hive', + endpoint: 'https://cdn.graphql-hive.com/', + token: '' + } +}) +``` diff --git a/.changeset/happy-eels-speak.md b/.changeset/happy-eels-speak.md new file mode 100644 index 0000000000000..6064e3c955ebd --- /dev/null +++ b/.changeset/happy-eels-speak.md @@ -0,0 +1,5 @@ +--- +'@graphql-mesh/plugin-hive': patch +--- + +Support truthy DEBUG environment variables (1, t, true, y, yes) diff --git a/.changeset/sour-lemons-think.md b/.changeset/sour-lemons-think.md new file mode 100644 index 0000000000000..ba9601cbaa119 --- /dev/null +++ b/.changeset/sour-lemons-think.md @@ -0,0 +1,36 @@ +--- +'@graphql-mesh/types': minor +'@graphql-mesh/plugin-hive': minor +--- + +Support Hive's experimental persisted documents + +```ts +import { useMeshHive } from '@graphql-mesh/plugin-hive' + +// Usage Reporting +useMeshHive({ + token: '' +}) + +// Persisted Documents +useMeshHive({ + experimental__persistedDocuments: { + cdn: { + endpoint: 'https://cdn.graphql-hive.com/', + accessToken: '' + } + } +}) + +// Usage Reporting and Persisted Documents +useMeshHive({ + token: '', + experimental__persistedDocuments: { + cdn: { + endpoint: 'https://cdn.graphql-hive.com/', + accessToken: '' + } + } +}) +``` diff --git a/.changeset/tidy-rocks-shave.md b/.changeset/tidy-rocks-shave.md new file mode 100644 index 0000000000000..6bf2b6c366093 --- /dev/null +++ b/.changeset/tidy-rocks-shave.md @@ -0,0 +1,17 @@ +--- +'@graphql-mesh/serve-runtime': minor +--- + +Support Hive's experimental persisted documents + +```ts +import { createServeRuntime } from '@graphql-mesh/serve-runtime' + +createServeRuntime({ + persistedDocuments: { + type: 'hive', + endpoint: 'https://cdn.graphql-hive.com/', + token: '' + } +}) +``` diff --git a/packages/legacy/types/src/config-schema.json b/packages/legacy/types/src/config-schema.json index ce8a42e5aa434..db7aa9800c10a 100644 --- a/packages/legacy/types/src/config-schema.json +++ b/packages/legacy/types/src/config-schema.json @@ -2025,7 +2025,7 @@ }, "token": { "type": "string", - "description": "Access Token" + "description": "Access Token for Usage Reporting" }, "agent": { "$ref": "#/definitions/HiveAgentOptions", @@ -2042,9 +2042,12 @@ "selfHosting": { "$ref": "#/definitions/HiveSelfHostingOptions", "description": "Options for self-hosting\n[See more](https://github.com/kamilkisiela/graphql-hive/tree/main/packages/libraries/client#self-hosting)" + }, + "experimental__persistedDocuments": { + "$ref": "#/definitions/HivePersistedDocumentsConfiguration", + "description": "Experimental persisted documents configuration\n[See more](https://the-guild.dev/graphql/hive/docs/features/app-deployments#persisted-documents-on-graphql-server-and-gateway)" } - }, - "required": ["token"] + } }, "HiveAgentOptions": { "additionalProperties": false, @@ -2198,6 +2201,42 @@ }, "required": ["graphqlEndpoint", "applicationUrl"] }, + "HivePersistedDocumentsConfiguration": { + "additionalProperties": false, + "type": "object", + "title": "HivePersistedDocumentsConfiguration", + "properties": { + "cdn": { + "$ref": "#/definitions/HivePersistedDocumentsConfigurationCDN", + "description": "Point to your own instance of GraphQL Hive API\n\nUsed by schema reporting and token info." + }, + "allowArbitraryDocuments": { + "type": "boolean", + "description": "Whether arbitrary documents should be allowed along-side persisted documents. false by default" + }, + "cache": { + "type": "integer", + "description": "Maximum amount of operations that shall be kept in memory after being loaded from the CDN. 10 seconds by default" + } + }, + "required": ["cdn"] + }, + "HivePersistedDocumentsConfigurationCDN": { + "additionalProperties": false, + "type": "object", + "title": "HivePersistedDocumentsConfigurationCDN", + "properties": { + "endpoint": { + "type": "string", + "description": "CDN endpoint" + }, + "accessToken": { + "type": "string", + "description": "Access Token for Persisted Documents CDN" + } + }, + "required": ["endpoint", "accessToken"] + }, "HTTPCachePlugin": { "additionalProperties": false, "type": "object", diff --git a/packages/legacy/types/src/config.ts b/packages/legacy/types/src/config.ts index 4d3db997c95e4..0caa020cf2662 100644 --- a/packages/legacy/types/src/config.ts +++ b/packages/legacy/types/src/config.ts @@ -1874,13 +1874,14 @@ export interface HivePlugin { */ enabled?: boolean | string; /** - * Access Token + * Access Token for Usage Reporting */ - token: string; + token?: string; agent?: HiveAgentOptions; usage?: HiveUsageOptions; reporting?: HiveReportingOptions; selfHosting?: HiveSelfHostingOptions; + experimental__persistedDocuments?: HivePersistedDocumentsConfiguration; } /** * Agent Options @@ -1998,6 +1999,36 @@ export interface HiveSelfHostingOptions { */ usageEndpoint?: string; } +/** + * Experimental persisted documents configuration + * [See more](https://the-guild.dev/graphql/hive/docs/features/app-deployments#persisted-documents-on-graphql-server-and-gateway) + */ +export interface HivePersistedDocumentsConfiguration { + cdn: HivePersistedDocumentsConfigurationCDN; + /** + * Whether arbitrary documents should be allowed along-side persisted documents. false by default + */ + allowArbitraryDocuments?: boolean; + /** + * Maximum amount of operations that shall be kept in memory after being loaded from the CDN. 10 seconds by default + */ + cache?: number; +} +/** + * Point to your own instance of GraphQL Hive API + * + * Used by schema reporting and token info. + */ +export interface HivePersistedDocumentsConfigurationCDN { + /** + * CDN endpoint + */ + endpoint: string; + /** + * Access Token for Persisted Documents CDN + */ + accessToken: string; +} export interface HTTPCachePlugin { /** * If the following patterns match the request URL, the response will be cached. (Any of: String, URLPatternObj) diff --git a/packages/plugins/hive/src/index.ts b/packages/plugins/hive/src/index.ts index f6534d437e10a..810cc33fb36a8 100644 --- a/packages/plugins/hive/src/index.ts +++ b/packages/plugins/hive/src/index.ts @@ -20,19 +20,21 @@ export default function useMeshHive( : true; if (!enabled) { - pluginOptions.logger?.warn('Reporting is disabled'); + pluginOptions.logger?.warn('Plugin is disabled'); return {}; } const token = stringInterpolator.parse(pluginOptions.token, { env: process.env, }); - if (!token) { - pluginOptions.logger?.warn('Reporting is disabled because the "token" was not provided'); - return {}; + if (token) { + pluginOptions.logger?.info('Reporting enabled'); } - pluginOptions.logger?.info('Reporting enabled'); + const persistedDocuments = pluginOptions.experimental__persistedDocuments; + if (persistedDocuments) { + pluginOptions.logger?.info('Persisted documents enabled'); + } let usage: HivePluginOptions['usage'] = true; if (pluginOptions.usage) { @@ -105,8 +107,12 @@ export default function useMeshHive( }; } const hiveClient = createHive({ - enabled: true, - debug: !!process.env.DEBUG, + enabled: + // eslint-disable-next-line no-unneeded-ternary -- for brevity + persistedDocuments && !token + ? false // disable usage reporting if just persisted documents are configured + : true, + debug: ['1', 't', 'true', 'y', 'yes'].includes(process.env.DEBUG), token, agent, usage, @@ -114,6 +120,7 @@ export default function useMeshHive( selfHosting, // Mesh already disposes the client below on Mesh's `destroy` event autoDispose: false, + experimental__persistedDocuments: persistedDocuments, }); // TODO: Remove later after v0 // Pubsub.destroy will no longer diff --git a/packages/plugins/hive/yaml-config.graphql b/packages/plugins/hive/yaml-config.graphql index 5592384981671..a8715d3167405 100644 --- a/packages/plugins/hive/yaml-config.graphql +++ b/packages/plugins/hive/yaml-config.graphql @@ -9,9 +9,9 @@ type HivePlugin @md { """ enabled: BooleanOrString """ - Access Token + Access Token for Usage Reporting """ - token: String! + token: String """ Agent Options """ @@ -29,6 +29,11 @@ type HivePlugin @md { [See more](https://github.com/kamilkisiela/graphql-hive/tree/main/packages/libraries/client#self-hosting) """ selfHosting: HiveSelfHostingOptions + """ + Experimental persisted documents configuration + [See more](https://the-guild.dev/graphql/hive/docs/features/app-deployments#persisted-documents-on-graphql-server-and-gateway) + """ + experimental__persistedDocuments: HivePersistedDocumentsConfiguration } type HiveAgentOptions { @@ -138,3 +143,31 @@ type HiveSelfHostingOptions { """ usageEndpoint: String } + +type HivePersistedDocumentsConfiguration { + """ + Point to your own instance of GraphQL Hive API + + Used by schema reporting and token info. + """ + cdn: HivePersistedDocumentsConfigurationCDN! + """ + Whether arbitrary documents should be allowed along-side persisted documents. false by default + """ + allowArbitraryDocuments: Boolean + """ + Maximum amount of operations that shall be kept in memory after being loaded from the CDN. 10 seconds by default + """ + cache: Int +} + +type HivePersistedDocumentsConfigurationCDN { + """ + CDN endpoint + """ + endpoint: String! + """ + Access Token for Persisted Documents CDN + """ + accessToken: String! +} diff --git a/packages/serve-cli/src/cli.ts b/packages/serve-cli/src/cli.ts index 4e170769e0a6a..cc660fe2124a8 100644 --- a/packages/serve-cli/src/cli.ts +++ b/packages/serve-cli/src/cli.ts @@ -6,17 +6,14 @@ import cluster from 'node:cluster'; import { availableParallelism, release } from 'node:os'; import parseDuration from 'parse-duration'; import { Command, InvalidArgumentError, Option } from '@commander-js/extra-typings'; -import type { - MeshServeConfigProxy, - MeshServeConfigSubgraph, - MeshServeConfigSupergraph, -} from '@graphql-mesh/serve-runtime'; +import type { MeshServeConfigProxy, MeshServeConfigSubgraph, MeshServeConfigSupergraph } from '@graphql-mesh/serve-runtime'; import type { Logger } from '@graphql-mesh/types'; import { DefaultLogger } from '@graphql-mesh/utils'; import { addCommands } from './commands/index.js'; import { defaultConfigPaths } from './config.js'; import type { ServerConfig } from './server'; + export type MeshServeCLIConfig = ( | MeshServeCLISupergraphConfig | MeshServeCLISubgraphConfig @@ -179,6 +176,14 @@ let cli = new Command() 'Hive registry token for usage metrics reporting', ).env('HIVE_REGISTRY_TOKEN'), ) + .option( + '--hive-persisted-documents-endpoint ', + '[EXPERIMENTAL] Hive CDN endpoint for fetching the persisted documents. requires the "--hive-persisted-documents-token " option', + ) + .option( + '--hive-persisted-documents-token ', + '[EXPERIMENTAL] Hive persisted documents CDN endpoint. requires the "--hive-persisted-documents-endpoint " option', + ) .addOption( new Option( '--apollo-graph-ref ', diff --git a/packages/serve-cli/src/commands/proxy.ts b/packages/serve-cli/src/commands/proxy.ts index d40ceb4c7af51..e06fc90eed1ff 100644 --- a/packages/serve-cli/src/commands/proxy.ts +++ b/packages/serve-cli/src/commands/proxy.ts @@ -30,8 +30,16 @@ export const addCommand: AddCommand = (ctx, cli) => ).env('HIVE_CDN_KEY'), ) .action(async function proxy(endpoint) { - const { hiveCdnKey, hiveRegistryToken, maskedErrors, polling, nativeImport, ...opts } = - this.optsWithGlobals(); + const { + hiveCdnKey, + hiveRegistryToken, + maskedErrors, + polling, + nativeImport, + hivePersistedDocumentsEndpoint, + hivePersistedDocumentsToken, + ...opts + } = this.optsWithGlobals(); const loadedConfig = await loadConfig({ log: ctx.log, configPath: opts.configPath, @@ -87,6 +95,16 @@ export const addCommand: AddCommand = (ctx, cli) => } : {}), ...(polling ? { pollingInterval: polling } : {}), + ...(hivePersistedDocumentsEndpoint + ? { + persistedDocuments: { + type: 'hive', + endpoint: + hivePersistedDocumentsEndpoint || loadedConfig.persistedDocuments?.endpoint, + token: hivePersistedDocumentsToken || loadedConfig.persistedDocuments?.token, + }, + } + : {}), proxy, schema, logging: loadedConfig.logging ?? ctx.log, diff --git a/packages/serve-cli/src/commands/subgraph.ts b/packages/serve-cli/src/commands/subgraph.ts index 652b2f32d198d..9c38404e2468e 100644 --- a/packages/serve-cli/src/commands/subgraph.ts +++ b/packages/serve-cli/src/commands/subgraph.ts @@ -29,8 +29,15 @@ export const addCommand: AddCommand = (ctx, cli) => 'path to the subgraph schema file or a url from where to pull the subgraph schema (default: "subgraph.graphql")', ) .action(async function subgraph(schemaPathOrUrl) { - const { maskedErrors, hiveRegistryToken, polling, nativeImport, ...opts } = - this.optsWithGlobals(); + const { + maskedErrors, + hiveRegistryToken, + polling, + nativeImport, + hivePersistedDocumentsEndpoint, + hivePersistedDocumentsToken, + ...opts + } = this.optsWithGlobals(); const loadedConfig = await loadConfig({ log: ctx.log, configPath: opts.configPath, @@ -59,6 +66,16 @@ export const addCommand: AddCommand = (ctx, cli) => } : {}), ...(polling ? { pollingInterval: polling } : {}), + ...(hivePersistedDocumentsEndpoint + ? { + persistedDocuments: { + type: 'hive', + endpoint: + hivePersistedDocumentsEndpoint || loadedConfig.persistedDocuments?.endpoint, + token: hivePersistedDocumentsToken || loadedConfig.persistedDocuments?.token, + }, + } + : {}), subgraph, logging: loadedConfig.logging ?? ctx.log, }; diff --git a/packages/serve-cli/src/commands/supergraph.ts b/packages/serve-cli/src/commands/supergraph.ts index 2ad0643d748a3..6bcd71bc98f9c 100644 --- a/packages/serve-cli/src/commands/supergraph.ts +++ b/packages/serve-cli/src/commands/supergraph.ts @@ -53,6 +53,8 @@ export const addCommand: AddCommand = (ctx, cli) => apolloGraphRef, apolloKey, apolloUplink, + hivePersistedDocumentsEndpoint, + hivePersistedDocumentsToken, ...opts } = this.optsWithGlobals(); const loadedConfig = await loadConfig({ @@ -111,6 +113,16 @@ export const addCommand: AddCommand = (ctx, cli) => ...opts, ...registryConfig, ...(polling ? { pollingInterval: polling } : {}), + ...(hivePersistedDocumentsEndpoint + ? { + persistedDocuments: { + type: 'hive', + endpoint: + hivePersistedDocumentsEndpoint || loadedConfig.persistedDocuments?.endpoint, + token: hivePersistedDocumentsToken || loadedConfig.persistedDocuments?.token, + }, + } + : {}), supergraph, logging: loadedConfig.logging ?? ctx.log, }; diff --git a/packages/serve-runtime/src/createServeRuntime.ts b/packages/serve-runtime/src/createServeRuntime.ts index 19c1db706cf28..c35692437161e 100644 --- a/packages/serve-runtime/src/createServeRuntime.ts +++ b/packages/serve-runtime/src/createServeRuntime.ts @@ -24,6 +24,7 @@ import { restoreExtraDirectives, UnifiedGraphManager, } from '@graphql-mesh/fusion-runtime'; +import useMeshHive from '@graphql-mesh/plugin-hive'; import type { Logger, OnDelegateHook, OnFetchHook } from '@graphql-mesh/types'; import { DefaultLogger, @@ -118,6 +119,20 @@ export function createServeRuntime = Record let contextBuilder: (context: T) => MaybePromise; let readinessChecker: () => MaybePromise; const registryPlugin = getRegistryPlugin(config, configContext); + let persistedDocumentsPlugin: MeshServePlugin = {}; + if (config.reporting?.type !== 'hive' && config.persistedDocuments?.type === 'hive') { + persistedDocumentsPlugin = useMeshHive({ + ...configContext, + logger: configContext.logger.child('Hive'), + experimental__persistedDocuments: { + cdn: { + endpoint: config.persistedDocuments.endpoint, + accessToken: config.persistedDocuments.token, + }, + allowArbitraryDocuments: config.persistedDocuments.allowArbitraryDocuments, + }, + }); + } let subgraphInformationHTMLRenderer: () => MaybePromise = () => ''; const disposableStack = new AsyncDisposableStack(); @@ -688,6 +703,7 @@ export function createServeRuntime = Record unifiedGraphPlugin, readinessCheckPlugin, registryPlugin, + persistedDocumentsPlugin, useChangingSchema(getSchema, _setSchema => { setSchema = _setSchema; }), diff --git a/packages/serve-runtime/src/getRegistryPlugin.ts b/packages/serve-runtime/src/getRegistryPlugin.ts index fdc5acd8618b5..f5556247e948a 100644 --- a/packages/serve-runtime/src/getRegistryPlugin.ts +++ b/packages/serve-runtime/src/getRegistryPlugin.ts @@ -16,6 +16,16 @@ export function getRegistryPlugin( ...configContext, logger: configContext.logger.child('Hive'), ...config.reporting, + experimental__persistedDocuments: + config.persistedDocuments?.type === 'hive' + ? { + cdn: { + endpoint: config.persistedDocuments.endpoint, + accessToken: config.persistedDocuments.token, + }, + allowArbitraryDocuments: config.persistedDocuments.allowArbitraryDocuments, + } + : undefined, }), }; } else if ( diff --git a/packages/serve-runtime/src/types.ts b/packages/serve-runtime/src/types.ts index 35bcf9db443cf..4e848b69967e5 100644 --- a/packages/serve-runtime/src/types.ts +++ b/packages/serve-runtime/src/types.ts @@ -150,7 +150,8 @@ export interface MeshServeHiveCDNOptions { key: string; } -export interface MeshServeHiveReportingOptions extends YamlConfig.HivePlugin { +export interface MeshServeHiveReportingOptions + extends Omit { type: 'hive'; /** GraphQL Hive registry access token. */ token: string; @@ -211,9 +212,34 @@ export interface MeshServeGraphOSReportingOptions extends MeshServeGraphOSOption endpoint?: string; } +/** + * Use Hive's CDN for persisted documents. + * + * [See more.](https://the-guild.dev/graphql/hive/docs/features/app-deployments#persisted-documents-on-graphql-server-and-gateway) + * */ +export interface MeshServeHivePersistedDocumentsOptions { + type: 'hive'; + /** + * GraphQL Hive persisted documents CDN endpoint URL. + */ + endpoint: string; + /** + * GraphQL Hive persisted documents CDN access token. + */ + token: string; + /** + * Whether arbitrary documents should be allowed along-side persisted documents. + * + * @default false + */ + allowArbitraryDocuments?: boolean; +} + interface MeshServeConfigBase> { /** Usage reporting options. */ reporting?: MeshServeHiveReportingOptions | MeshServeGraphOSReportingOptions; + /** Persisted documents options. */ + persistedDocuments?: MeshServeHivePersistedDocumentsOptions; /** * A map, or factory function, of transport kinds to their implementations. * diff --git a/website/src/generated-markdown/HivePlugin.generated.md b/website/src/generated-markdown/HivePlugin.generated.md index 50bf7505c6182..112b39fd6564f 100644 --- a/website/src/generated-markdown/HivePlugin.generated.md +++ b/website/src/generated-markdown/HivePlugin.generated.md @@ -3,7 +3,7 @@ You can use environment variables expression, for example: `process.env.MOCKING_ENABLED != null` One of: * `Boolean` * `String` -* `token` (type: `String`, required) - Access Token +* `token` (type: `String`) - Access Token for Usage Reporting * `agent` (type: `Object`) - Agent Options: * `name` (type: `String`) * `logger` (type: `Any`) @@ -47,4 +47,13 @@ Used by schema reporting and token info. Used by token info to generate a link to the organization, project and target. * `usageEndpoint` (type: `String`) - Point to your own instance of GraphQL Hive Usage API -Used by usage reporting. \ No newline at end of file +Used by usage reporting. +* `experimental__persistedDocuments` (type: `Object`) - Experimental persisted documents configuration +[See more](https://the-guild.dev/graphql/hive/docs/features/app-deployments#persisted-documents-on-graphql-server-and-gateway): + * `cdn` (type: `Object`, required) - Point to your own instance of GraphQL Hive API + +Used by schema reporting and token info.: + * `endpoint` (type: `String`, required) - CDN endpoint + * `accessToken` (type: `String`, required) - Access Token for Persisted Documents CDN + * `allowArbitraryDocuments` (type: `Boolean`) - Whether arbitrary documents should be allowed along-side persisted documents. false by default + * `cache` (type: `Int`) - Maximum amount of operations that shall be kept in memory after being loaded from the CDN. 10 seconds by default \ No newline at end of file diff --git a/website/src/pages/v1/serve/features/performance/persisted-operations.mdx b/website/src/pages/v1/serve/features/performance/persisted-operations.mdx index 73262fd91d659..cb6195bf438a2 100644 --- a/website/src/pages/v1/serve/features/performance/persisted-operations.mdx +++ b/website/src/pages/v1/serve/features/performance/persisted-operations.mdx @@ -27,8 +27,8 @@ persisted operations. You can go to the dedicated page for the schema registry you are using to learn how to enable persisted operations. -- [Hive](/v1/serve/features/schema-registry/hive) -- [GraphOS](/v1/serve/features/schema-registry/graphos) +- [Hive](/v1/serve/schema-registry/hive) +- [GraphOS](/v1/serve/schema-registry/graphos) ## Plugin for custom handling diff --git a/website/src/pages/v1/serve/schema-registry/hive.mdx b/website/src/pages/v1/serve/schema-registry/hive.mdx index c23cb3b780af7..4e3f0d6696722 100644 --- a/website/src/pages/v1/serve/schema-registry/hive.mdx +++ b/website/src/pages/v1/serve/schema-registry/hive.mdx @@ -85,3 +85,53 @@ export const serveConfig = defineConfig({ Refer to to the [Hive Client documentation](https://the-guild.dev/graphql/hive/docs/api-reference/client#configuration) for further customization, such as usage reporting sampling and more. + +## Persisted Documents + +Persisted documents can be used on your GraphQL server or Gateway to reduce the payload size of your +GraphQL requests and secure your GraphQL API by only allowing operations that are known and trusted +by your Gateway. GraphQL Hive can serve as a CDN for the persisted documents as they're requested. + +Make sure you have configured **Persisted Documents** on GraphQL Hive as described +[here](https://the-guild.dev/graphql/hive/docs/features/app-deployments#persisted-documents-on-graphql-server-and-gateway). + +### Configuration + +After getting `endpoint` and `token` from GraphQL Hive, you can enable persisted documents in Mesh +Serve. + +```sh filename="Run the Mesh Serve CLI" +npx mesh-serve supergraph "" --hive-persisted-documents-token "" < endpoint > --hive-persisted-documents-endpoint +``` + +Or you can use a configuration file: + +```ts filename="mesh.config.ts" +import { defineConfig } from '@graphql-mesh/serve-cli' + +export const serveConfig = defineConfig({ + persistedDocuments: { + type: 'hive', + endpoint: '', + token: '' + } +}) +``` + +#### Enabling Arbitrary Documents (not recommended) + +By default, Mesh Server only allows persisted documents that are known and trusted by your Gateway. +If you want to allow arbitrary documents, you can enable the `allowArbitraryDocuments` option: + +```ts filename="mesh.config.ts" +import { defineConfig } from '@graphql-mesh/serve-cli' + +export const serveConfig = defineConfig({ + persistedDocuments: { + type: 'hive', + endpoint: '', + token: '', + allowArbitraryDocuments: true + } +}) +```