graphql-ws
Advanced tools
Comparing version 1.9.3 to 1.10.0
@@ -0,1 +1,9 @@ | ||
# [1.10.0](https://github.com/enisdenjo/graphql-ws/compare/v1.9.3...v1.10.0) (2020-11-03) | ||
### Features | ||
* Subscribe message `query` must be a string ([#45](https://github.com/enisdenjo/graphql-ws/issues/45)) ([60d9cd5](https://github.com/enisdenjo/graphql-ws/commit/60d9cd5509d1b989f3ca6a9370850ce0aae41522)) | ||
* **server:** For dynamic usage, `context` option can be a function too ([#46](https://github.com/enisdenjo/graphql-ws/issues/46)) ([149b582](https://github.com/enisdenjo/graphql-ws/commit/149b58266859d6f275c186581f71c3aff52cb4a3)) | ||
## [1.9.3](https://github.com/enisdenjo/graphql-ws/compare/v1.9.2...v1.9.3) (2020-10-31) | ||
@@ -2,0 +10,0 @@ |
@@ -6,3 +6,3 @@ /** | ||
*/ | ||
import { GraphQLError, ExecutionResult, DocumentNode } from 'graphql'; | ||
import { GraphQLError, ExecutionResult } from 'graphql'; | ||
/** Types of messages allowed to be sent by the client/server over the WS protocol. */ | ||
@@ -31,3 +31,3 @@ export declare enum MessageType { | ||
readonly operationName?: string | null; | ||
readonly query: string | DocumentNode; | ||
readonly query: string; | ||
readonly variables?: Record<string, unknown> | null; | ||
@@ -34,0 +34,0 @@ } |
@@ -43,4 +43,3 @@ "use strict"; | ||
typeof val.payload.operationName === 'string') && | ||
(utils_1.hasOwnStringProperty(val.payload, 'query') || // string query or persisted query id | ||
utils_1.hasOwnObjectProperty(val.payload, 'query')) && // document node query | ||
utils_1.hasOwnStringProperty(val.payload, 'query') && | ||
(!utils_1.hasOwnProperty(val.payload, 'variables') || | ||
@@ -47,0 +46,0 @@ val.payload.variables === undefined || |
@@ -14,2 +14,11 @@ /** | ||
export declare type OperationResult = Promise<AsyncIterableIterator<ExecutionResult> | ExecutionResult> | AsyncIterableIterator<ExecutionResult> | ExecutionResult; | ||
/** | ||
* A concrete GraphQL execution context value type. | ||
* | ||
* Mainly used because TypeScript collapes unions | ||
* with `any` or `unknown` to `any` or `unknown`. So, | ||
* we use a custom type to allow definitions such as | ||
* the `context` server option. | ||
*/ | ||
export declare type GraphQLExecutionContextValue = object | symbol | number | string | boolean | null; | ||
export interface ServerOptions { | ||
@@ -30,7 +39,12 @@ /** | ||
* | ||
* If you return from the `onSubscribe` callback, this | ||
* context value will NOT be injected. You should add it | ||
* in the returned `ExecutionArgs` from the callback. | ||
* If you return from `onSubscribe`, and the returned value is | ||
* missing the `contextValue` field, this context will be used | ||
* instead. | ||
* | ||
* If you use the function signature, the final execution arguments | ||
* will be passed in (also the returned value from `onSubscribe`). | ||
* Since the context is injected on every subscribe, the `SubscribeMessage` | ||
* with the regular `Context` will be passed in through the arguments too. | ||
*/ | ||
context?: unknown; | ||
context?: GraphQLExecutionContextValue | ((ctx: Context, message: SubscribeMessage, args: ExecutionArgs) => GraphQLExecutionContextValue); | ||
/** | ||
@@ -119,3 +133,6 @@ * The GraphQL root fields or resolvers to go | ||
* for providing a ready set of arguments which will | ||
* be directly plugged in the operation execution. | ||
* be directly plugged in the operation execution. Beware, | ||
* the `context` server option is an exception. Only if you | ||
* dont provide a context alongside the returned value | ||
* here, the `context` server option will be used instead. | ||
* | ||
@@ -122,0 +139,0 @@ * To report GraphQL errors simply return an array |
@@ -212,3 +212,4 @@ "use strict"; | ||
} | ||
execArgs = maybeExecArgsOrErrors; // because not graphql errors | ||
// not errors, is exec args | ||
execArgs = maybeExecArgsOrErrors; | ||
} | ||
@@ -222,8 +223,6 @@ else { | ||
const { operationName, query, variables } = message.payload; | ||
const document = typeof query === 'string' ? graphql_1.parse(query) : query; | ||
execArgs = { | ||
contextValue: context, | ||
schema, | ||
operationName, | ||
document, | ||
document: graphql_1.parse(query), | ||
variableValues: variables, | ||
@@ -246,2 +245,10 @@ }; | ||
} | ||
// inject the context, if provided, before the operation. | ||
// but, only if the `onSubscribe` didnt provide one already | ||
if (context !== undefined && !execArgs.contextValue) { | ||
execArgs.contextValue = | ||
typeof context === 'function' | ||
? context(ctx, message, execArgs) | ||
: context; | ||
} | ||
// the execution arguments have been prepared | ||
@@ -302,3 +309,3 @@ // perform the operation and act accordingly | ||
catch (err) { | ||
// TODO-db-201031 we percieve this as a client bad request error, but is it always? | ||
// TODO-db-201031 we perceive this as a client bad request error, but is it always? | ||
ctx.socket.close(4400, err.message); | ||
@@ -305,0 +312,0 @@ } |
@@ -9,3 +9,3 @@ /** | ||
export declare function isAsyncIterable<T = unknown>(val: unknown): val is AsyncIterableIterator<T>; | ||
export declare function areGraphQLErrors(obj: unknown): obj is GraphQLError[]; | ||
export declare function areGraphQLErrors(obj: unknown): obj is readonly GraphQLError[]; | ||
export declare function hasOwnProperty<O extends Record<PropertyKey, unknown>, P extends PropertyKey>(obj: O, prop: P): obj is O & Record<P, unknown>; | ||
@@ -12,0 +12,0 @@ export declare function hasOwnObjectProperty<O extends Record<PropertyKey, unknown>, P extends PropertyKey>(obj: O, prop: P): obj is O & Record<P, Record<PropertyKey, unknown>>; |
{ | ||
"name": "graphql-ws", | ||
"version": "1.9.3", | ||
"version": "1.10.0", | ||
"description": "Coherent, zero-dependency, lazy, simple, GraphQL over WebSocket Protocol compliant server and client", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
@@ -65,4 +65,2 @@ # GraphQL over WebSocket Protocol | ||
```typescript | ||
import { DocumentNode } from 'graphql'; | ||
interface SubscribeMessage { | ||
@@ -73,3 +71,3 @@ id: '<unique-operation-id>'; | ||
operationName?: string | null; | ||
query: string | DocumentNode; | ||
query: string; | ||
variables?: Record<string, unknown> | null; | ||
@@ -76,0 +74,0 @@ }; |
@@ -275,2 +275,3 @@ <div align="center"> | ||
import { ApolloLink, Operation, FetchResult, Observable } from '@apollo/client'; | ||
import { print } from 'graphql'; | ||
import { createClient, Config, Client } from 'graphql-ws'; | ||
@@ -288,21 +289,26 @@ | ||
return new Observable((sink) => { | ||
return this.client.subscribe<FetchResult>(operation, { | ||
...sink, | ||
error: (err) => { | ||
if (err instanceof Error) { | ||
sink.error(err); | ||
} else if (err instanceof CloseEvent) { | ||
sink.error( | ||
new Error( | ||
`Socket closed with event ${err.code}` + err.reason | ||
? `: ${err.reason}` // reason will be available on clean closes | ||
: '', | ||
), | ||
); | ||
} else { | ||
// GraphQLError[] | ||
sink.error(new Error(err.map(({ message }) => message).join(', '))); | ||
} | ||
return this.client.subscribe<FetchResult>( | ||
{ ...operation, query: print(operation.query) }, | ||
{ | ||
...sink, | ||
error: (err) => { | ||
if (err instanceof Error) { | ||
sink.error(err); | ||
} else if (err instanceof CloseEvent) { | ||
sink.error( | ||
new Error( | ||
`Socket closed with event ${err.code}` + err.reason | ||
? `: ${err.reason}` // reason will be available on clean closes | ||
: '', | ||
), | ||
); | ||
} else { | ||
// GraphQLError[] | ||
sink.error( | ||
new Error(err.map(({ message }) => message).join(', ')), | ||
); | ||
} | ||
}, | ||
}, | ||
}); | ||
); | ||
}); | ||
@@ -396,2 +402,3 @@ } | ||
import { createServer } from 'graphql-ws'; | ||
import { schema } from 'my-graphql-schema'; | ||
@@ -495,3 +502,3 @@ const server = https.createServer(function weServeSocketsOnly(_, res) { | ||
<details> | ||
<summary>Server usage with custom static GraphQL arguments</summary> | ||
<summary>Server usage with custom context value</summary> | ||
@@ -501,7 +508,9 @@ ```typescript | ||
import { createServer } from 'graphql-ws'; | ||
import { schema, roots, getStaticContext } from 'my-graphql'; | ||
import { schema, roots, getDynamicContext } from 'my-graphql'; | ||
createServer( | ||
{ | ||
context: getStaticContext(), | ||
context: (ctx, msg, args) => { | ||
return getDynamicContext(ctx, msg, args); | ||
}, // or static context by supplying the value direcly | ||
schema, | ||
@@ -522,3 +531,3 @@ roots, | ||
<details> | ||
<summary>Server usage with custom dynamic GraphQL arguments and validation</summary> | ||
<summary>Server usage with custom execution arguments and validation</summary> | ||
@@ -528,3 +537,3 @@ ```typescript | ||
import { createServer } from 'graphql-ws'; | ||
import { schema, getDynamicContext, myValidationRules } from 'my-graphql'; | ||
import { schema, myValidationRules } from 'my-graphql'; | ||
@@ -538,5 +547,4 @@ createServer( | ||
schema, | ||
contextValue: getDynamicContext(ctx, msg), | ||
operationName: msg.payload.operationName, | ||
document: parse(msg.payload.operationName), | ||
document: parse(msg.payload.query), | ||
variableValues: msg.payload.variables, | ||
@@ -543,0 +551,0 @@ }; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
101583
1332
652
5