diff --git a/.config/beemo/prettier.ts b/.config/beemo/prettier.ts index 600d5ca56..26288ac94 100644 --- a/.config/beemo/prettier.ts +++ b/.config/beemo/prettier.ts @@ -2,6 +2,8 @@ import { PrettierConfig } from '@beemo/driver-prettier'; const config: PrettierConfig = { ignore: ['deno'], + useTabs: false, + tabWidth: 2, }; export default config; diff --git a/docs/plugins/errors.md b/docs/plugins/errors.md new file mode 100644 index 000000000..0b1d556f5 --- /dev/null +++ b/docs/plugins/errors.md @@ -0,0 +1,201 @@ +--- +name: Errors +menu: Plugins +--- + +# Errors Plugin + +A plugin for easily including errors in your GraphQL schema. + +## Usage + +### Install + +```bash +yarn add @giraphql/plugin-errors +``` + +### Example Ussage + +```typescript +import ErrorsPlugin from '@giraphql/plugin-errors'; +const builder = new SchemaBuilder({ + plugins: [ErrorsPlugin], + errorOptions: { + defaultTypes: [], + }, +}); + +builder.objectType(Error, { + name: 'Error', + fields: (t) => ({ + message: t.exposeString('message'), + }), +}); + +builder.queryType({ + fields: (t) => ({ + hello: t.string({ + errors: { + type: [Error], + }, + args: { + name: t.arg.string({ required: false }), + }, + resolve: (parent, { name }) => { + if (name.slice(0, 1) !== name.slice(0, 1).toUpperCase()) { + throw new Error('name must be capitalized'); + } + + return `hello, ${name || 'World'}`; + }, + }), + }), +}); +``` + +The above example will produce a GraphQL schema that looks like: + +```graphql +type Error { + message: String! +} + +type Query { + hello(name: String!): QueryHelloResult +} + +union QueryExtendedErrorListOrError = Error | QueryHelloSuccess + +type QueryHelloSuccess { + data: String! +} +``` + +This field can be queried using fragments like: + +```graphql +query { + hello(name: "World") { + __typename + ... on Error { + message + } + ... on QueryHelloSuccess { + data + } + } +} +``` + +This plugin works by wrapping fields that define error options in a union type. This union consists +of an object type for each error type defined for the field, and a Success object type that wraps +the returned data. If the fields resolver throws an instance of one of the defined errors, the +errors plugin will automatically resolve to the corresponding error object type. + +### Builder options + +- `defaultTypes`: An array of Error classes to include in every field with error handling. + +### Options on Fields + +- `types`: An array of Error classes to catch and handle as error objects in the schema. Will be + merged with `defaultTypes` from builder. +- `union`: An options object for the union type. Can include any normal union type options, and + `name` option for setting a custom name for the union type. +- `result`: An options object for result object type. Can include any normal object type options, + and `name` option for setting a custom name for the result type. +- `dataField`: An options object for the data field on the result object. This field will be named + `data` by default, but can be written by passsing a custom `name` option. + +### Recommended Ussage + +1. Set up an Error interface +2. Create a BaseError object type +3. Include the Error interface in any custom Error types you define +4. Include the BaseError type in the `defaultTypes` in the builder config + +This pattern will allow you to consistently query your schema using a `... on Error { message }` +fragment since all Error classes extend that interface. If your client want's to query details of +more specialized error types, they can just add a fragment for the errors it cares about. This +pattern should also make it easier to make future changes without unexpected breaking changes for +your clients. + +The follow is a small example of this pattern: + +```typescript +import ErrorsPlugin from '@giraphql/plugin-errors'; +const builder = new SchemaBuilder({ + plugins: [ErrorsPlugin], + errorOptions: { + defaultTypes: [Error], + }, +}); + +const ErrorInterface = builder.interfaceRef('Error').implement({ + fields: (t) => ({ + message: t.exposeString('message'), + }), +}); + +builder.objectType(Error, { + name: 'BaseError', + isTypeOf: (obj) => obj instanceof Error, + interfaces: [ErrorInterface], +}); + +class LengthError extends Error { + minLength: number; + + constructor(minLength: number) { + super(`string length should be at least ${minLength}`); + + this.minLength = minLength; + this.name = 'LengthError'; + } +} + +builder.objectType(LengthError, { + name: 'LengthError', + interfaces: [ErrorInterface], + isTypeOf: (obj) => obj instanceof LengthError, + fields: (t) => ({ + minLength: t.exposeInt('minLength'), + }), +}); + +builder.queryType({ + fields: (t) => ({ + // Simple error handling just using base error class + hello: t.string({ + errors: {}, + args: { + name: t.arg.string({ required: true }), + }, + resolve: (parent, { name }) => { + if (!name.startsWith(name.slice(0, 1).toUpperCase())) { + throw new Error('name must be capitalized'); + } + + return `hello, ${name || 'World'}`; + }, + }), + // Handling custom errors + helloWithMinLength: t.string({ + errors: { + types: [LengthError], + }, + args: { + name: t.arg.string({ required: true }), + }, + resolve: (parent, { name }) => { + if (name.length < 5) { + throw new LengthError(5); + } + + return `hello, ${name || 'World'}`; + }, + }), + }), +}); +``` diff --git a/package.json b/package.json index 0125186ae..1a8797893 100644 --- a/package.json +++ b/package.json @@ -31,11 +31,11 @@ "devDependencies": { "@beemo/dev": "^0.1.8", "@types/jest": "^26.0.22", - "@types/node": "^15.12.0", + "@types/node": "^15.12.5", "@types/node-fetch": "^2.5.10", "conventional-changelog-beemo": "^2.1.0", "eslint-plugin-prettier": "^3.3.1", - "graphql": "^15.5.0", + "graphql": "^15.5.1", "husky": "^6.0.0", "lerna": "^4.0.0", "lint-staged": "^11.0.0", @@ -45,7 +45,7 @@ "typescript": "4.2.4" }, "resolutions": { - "graphql": "15.5.0" + "graphql": "15.5.1" }, "lint-staged": { "./src/**/*.{ts,tsx}": [ @@ -71,6 +71,6 @@ }, "homepage": "https://github.com/hayes/giraphql#readme", "dependencies": { - "zod": "3.1.0" + "zod": "3.2.0" } } diff --git a/packages/converter/package.json b/packages/converter/package.json index c51126b3b..9cd2cc0d9 100644 --- a/packages/converter/package.json +++ b/packages/converter/package.json @@ -24,7 +24,7 @@ "access": "public" }, "dependencies": { - "graphql": "^15.5.0", + "graphql": "^15.5.1", "ts-morph": "^11.0.0", "yargs": "^17.0.1" }, diff --git a/packages/core/package.json b/packages/core/package.json index c86ee7b32..811d404ad 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -31,9 +31,9 @@ "graphql": ">=15.1.0" }, "devDependencies": { - "apollo-server": "^2.25.0", - "graphql": ">=15.1.0", - "graphql-scalars": "^1.9.0", - "graphql-tag": "^2.11.0" + "apollo-server": "^2.25.2", + "graphql": ">=15.5.1", + "graphql-scalars": "^1.10.0", + "graphql-tag": "^2.12.5" } } diff --git a/packages/core/src/build-cache.ts b/packages/core/src/build-cache.ts index 94206938b..a514da520 100644 --- a/packages/core/src/build-cache.ts +++ b/packages/core/src/build-cache.ts @@ -433,12 +433,14 @@ export default class BuildCache { return ref.type; } - const { name } = this.configStore.getTypeConfig(ref); + const typeConfig = this.configStore.getTypeConfig(ref); - const type = this.types.get(name); + const type = this.types.get(typeConfig.name); if (!type) { - throw new TypeError(`Missing implementation of for type ${name}`); + this.buildTypeFromConfig(typeConfig); + + return this.types.get(typeConfig.name)!; } return type; diff --git a/packages/core/src/builder.ts b/packages/core/src/builder.ts index 34b443e4c..78bb2d3b5 100644 --- a/packages/core/src/builder.ts +++ b/packages/core/src/builder.ts @@ -131,9 +131,9 @@ export default class SchemaBuilder { throw new Error(`Invalid object name ${name} use .create${name}Type() instead`); } - const ref: ObjectRef, ParentShape> = + const ref = param instanceof ObjectRef - ? param + ? (param as ObjectRef, ParentShape>) : new ObjectRef, ParentShape>(name); const config: GiraphQLObjectTypeConfig = { @@ -159,7 +159,11 @@ export default class SchemaBuilder { } if (options.fields) { - this.configStore.addFields(ref, () => options.fields!(new ObjectFieldBuilder(name, this))); + this.configStore.addFields(ref, () => { + const t = new ObjectFieldBuilder>(name, this); + + return options.fields!(t); + }); } return ref; diff --git a/packages/core/src/utils/index.ts b/packages/core/src/utils/index.ts index 11e62657b..228443463 100644 --- a/packages/core/src/utils/index.ts +++ b/packages/core/src/utils/index.ts @@ -2,6 +2,7 @@ export * from './context-cache'; export * from './enums'; export * from './input'; export * from './params'; +export * from './sort-classes'; export function assertNever(value: never): never { throw new TypeError(`Unexpected value: ${value}`); diff --git a/packages/core/src/utils/sort-classes.ts b/packages/core/src/utils/sort-classes.ts new file mode 100644 index 000000000..286ec0a74 --- /dev/null +++ b/packages/core/src/utils/sort-classes.ts @@ -0,0 +1,25 @@ +export function classDepth(obj: {}): number { + const proto = Object.getPrototypeOf(obj) as {} | null; + + if (!proto) { + return 0; + } + + return 1 + classDepth(proto); +} + +export function sortClasses unknown>(classes: T[]) { + return [...classes].sort((a, b) => { + const depthA = classDepth(a); + const depthB = classDepth(b); + + if (depthA > depthB) { + return -1; + } + if (depthB > depthA) { + return 1; + } + + return 0; + }); +} diff --git a/packages/deno/package.json b/packages/deno/package.json index 1f612905b..219477132 100644 --- a/packages/deno/package.json +++ b/packages/deno/package.json @@ -12,6 +12,6 @@ "access": "public" }, "devDependencies": { - "ts-node": "^2.1.1" + "ts-node": "^10.0.0" } } diff --git a/packages/deno/packages/core/build-cache.ts b/packages/deno/packages/core/build-cache.ts index 26429f797..ba1c3674e 100644 --- a/packages/deno/packages/core/build-cache.ts +++ b/packages/deno/packages/core/build-cache.ts @@ -274,10 +274,11 @@ export default class BuildCache { if (ref instanceof BuiltinScalarRef) { return ref.type; } - const { name } = this.configStore.getTypeConfig(ref); - const type = this.types.get(name); + const typeConfig = this.configStore.getTypeConfig(ref); + const type = this.types.get(typeConfig.name); if (!type) { - throw new TypeError(`Missing implementation of for type ${name}`); + this.buildTypeFromConfig(typeConfig); + return this.types.get(typeConfig.name)!; } return type; } diff --git a/packages/deno/packages/core/builder.ts b/packages/deno/packages/core/builder.ts index 4c5874d1f..817491dd8 100644 --- a/packages/deno/packages/core/builder.ts +++ b/packages/deno/packages/core/builder.ts @@ -46,8 +46,8 @@ export default class SchemaBuilder { if (name === "Query" || name === "Mutation" || name === "Subscription") { throw new Error(`Invalid object name ${name} use .create${name}Type() instead`); } - const ref: ObjectRef, ParentShape> = param instanceof ObjectRef - ? param + const ref = param instanceof ObjectRef + ? (param as ObjectRef, ParentShape>) : new ObjectRef, ParentShape>(name); const config: GiraphQLObjectTypeConfig = { kind: "Object", @@ -66,7 +66,10 @@ export default class SchemaBuilder { this.configStore.addFields(ref, () => fields(new ObjectFieldBuilder>(name, this))); } if (options.fields) { - this.configStore.addFields(ref, () => options.fields!(new ObjectFieldBuilder(name, this))); + this.configStore.addFields(ref, () => { + const t = new ObjectFieldBuilder>(name, this); + return options.fields!(t); + }); } return ref; } diff --git a/packages/deno/packages/core/fieldUtils/builder.ts b/packages/deno/packages/core/fieldUtils/builder.ts index deafba3f4..826f7b780 100644 --- a/packages/deno/packages/core/fieldUtils/builder.ts +++ b/packages/deno/packages/core/fieldUtils/builder.ts @@ -2,6 +2,11 @@ import { CompatibleTypes, FieldKind, FieldNullability, FieldOptionsFromKind, NormalizeArgs, RootName, SchemaTypes, TypeParam, } from '../types/index.ts'; import RootFieldBuilder from './root.ts'; export default class FieldBuilder = Exclude> extends RootFieldBuilder { + /** + * Create a Boolean field from a boolean property on the parent object + * @param {string} name - the name of the property on the source object (does not need to match the field name). + * @param {object} [options={}] - Options for this field + */ exposeBoolean, ResolveReturnShape, Nullable extends FieldNullability<"Boolean"> = Types["DefaultFieldNullability"]>(...args: NormalizeArgs<[ name: Name, options?: Omit, "resolve" | "type"> @@ -9,6 +14,11 @@ export default class FieldBuilder(name, { ...options, type: "Boolean" }); } + /** + * Create a Float field from a numeric property on the parent object + * @param {string} name - the name of the property on the source object (does not need to match the field name). + * @param {object} [options={}] - Options for this field + */ exposeFloat, ResolveReturnShape, Nullable extends FieldNullability<"Float"> = Types["DefaultFieldNullability"]>(...args: NormalizeArgs<[ name: Name, options?: Omit, "resolve" | "type"> @@ -16,6 +26,11 @@ export default class FieldBuilder(name, { ...options, type: "Float" }); } + /** + * Create an ID field from a property on the parent object + * @param {string} name - the name of the property on the source object (does not need to match the field name). + * @param {object} [options={}] - Options for this field + */ exposeID, ResolveReturnShape, Nullable extends FieldNullability<"ID"> = Types["DefaultFieldNullability"]>(...args: NormalizeArgs<[ name: Name, options?: Omit, "resolve" | "type"> @@ -23,6 +38,11 @@ export default class FieldBuilder(name, { ...options, type: "ID" }); } + /** + * Create an Int field from a numeric property on the parent object + * @param {string} name - the name of the property on the source object (does not need to match the field name). + * @param {object} [options={}] - Options for this field + */ exposeInt, ResolveReturnShape, Nullable extends FieldNullability<"Int"> = Types["DefaultFieldNullability"]>(...args: NormalizeArgs<[ name: Name, options?: Omit, "args" | "resolve" | "type"> @@ -30,6 +50,11 @@ export default class FieldBuilder(name, { ...options, type: "Int" }); } + /** + * Create a String field from a string property on the parent object + * @param {string} name - the name of the property on the source object (does not need to match the field name). + * @param {object} [options={}] - Options for this field + */ exposeString, ResolveReturnShape, Nullable extends FieldNullability<"String"> = Types["DefaultFieldNullability"]>(...args: NormalizeArgs<[ name: Name, options?: Omit, "resolve" | "type"> @@ -37,6 +62,11 @@ export default class FieldBuilder(name, { ...options, type: "String" }); } + /** + * Create a Boolean list field from a boolean[] property on the parent object + * @param {string} name - the name of the property on the source object (does not need to match the field name). + * @param {object} [options={}] - Options for this field + */ exposeBooleanList, ResolveReturnShape, Nullable extends FieldNullability<[ @@ -52,6 +82,11 @@ export default class FieldBuilder(name, { ...options, type: ["Boolean"] }); } + /** + * Create a Float list field from a number[] property on the parent object + * @param {string} name - the name of the property on the source object (does not need to match the field name). + * @param {object} [options={}] - Options for this field + */ exposeFloatList, ResolveReturnShape, Nullable extends FieldNullability<[ @@ -67,6 +102,11 @@ export default class FieldBuilder(name, { ...options, type: ["Float"] }); } + /** + * Create an ID list field from an id[] property on the parent object + * @param {string} name - the name of the property on the source object (does not need to match the field name). + * @param {object} [options={}] - Options for this field + */ exposeIDList, ResolveReturnShape, Nullable extends FieldNullability<[ @@ -82,6 +122,11 @@ export default class FieldBuilder(name, { ...options, type: ["ID"] }); } + /** + * Create a Int list field from a number[] property on the parent object + * @param {string} name - the name of the property on the source object (does not need to match the field name). + * @param {object} [options={}] - Options for this field + */ exposeIntList, ResolveReturnShape, Nullable extends FieldNullability<[ @@ -97,6 +142,11 @@ export default class FieldBuilder(name, { ...options, type: ["Int"] }); } + /** + * Create a String list field from a string[] property on the parent object + * @param {string} name - the name of the property on the source object (does not need to match the field name). + * @param {object} [options={}] - Options for this field + */ exposeStringList, ResolveReturnShape, Nullable extends FieldNullability<[ @@ -112,6 +162,11 @@ export default class FieldBuilder(name, { ...options, type: ["String"] }); } + /** + * Create a field that resolves to a property of the corresponding type on the parent object + * @param {string} name - the name of the property on the source object (does not need to match the field name). + * @param {object} [options={}] - Options for this field + */ expose, Nullable extends boolean, ResolveReturnShape, Name extends CompatibleTypes>(...args: NormalizeArgs<[ name: Name, options?: Omit, "resolve"> diff --git a/packages/deno/packages/core/fieldUtils/input.ts b/packages/deno/packages/core/fieldUtils/input.ts index e8d7a12e0..83177132d 100644 --- a/packages/deno/packages/core/fieldUtils/input.ts +++ b/packages/deno/packages/core/fieldUtils/input.ts @@ -6,15 +6,55 @@ export default class InputFieldBuilder; kind: Kind; typename: string; + /** + * Create a Boolean input field + * @param {GiraphQLSchemaTypes.InputFieldOptions} [options={}] - Options for this field + */ boolean = this.helper("Boolean"); + /** + * Create a Float input field + * @param {GiraphQLSchemaTypes.InputFieldOptions} [options={}] - Options for this field + */ float = this.helper("Float"); + /** + * Create a ID input field + * @param {GiraphQLSchemaTypes.InputFieldOptions} [options={}] - Options for this field + */ id = this.helper("ID"); + /** + * Create a Int input field + * @param {GiraphQLSchemaTypes.InputFieldOptions} [options={}] - Options for this field + */ int = this.helper("Int"); + /** + * Create a String input field + * @param {GiraphQLSchemaTypes.InputFieldOptions} [options={}] - Options for this field + */ string = this.helper("String"); + /** + * Create a Boolean list input field + * @param {GiraphQLSchemaTypes.InputFieldOptions} [options={}] - Options for this field + */ booleanList = this.helper(["Boolean"]); + /** + * Create a Float list input field + * @param {GiraphQLSchemaTypes.InputFieldOptions} [options={}] - Options for this field + */ floatList = this.helper(["Float"]); + /** + * Create a ID list input field + * @param {GiraphQLSchemaTypes.InputFieldOptions} [options={}] - Options for this field + */ idList = this.helper(["ID"]); + /** + * Create a Int list input field + * @param {GiraphQLSchemaTypes.InputFieldOptions} [options={}] - Options for this field + */ intList = this.helper(["Int"]); + /** + * Create a String list input field + * @param {GiraphQLSchemaTypes.InputFieldOptions} [options={}] - Options for this field + */ stringList = this.helper(["String"]); constructor(builder: GiraphQLSchemaTypes.SchemaBuilder, kind: Kind, typename: string) { this.builder = builder; @@ -31,6 +71,10 @@ export default class InputFieldBuilder; } + /** + * Create in input field or argument for the current type + * @param {GiraphQLSchemaTypes.InputFieldOptions} [options={}] - Options for this field + */ field | [ InputType ], Req extends FieldRequiredness>(options: GiraphQLSchemaTypes.InputFieldOptionsByKind[Kind]) { diff --git a/packages/deno/packages/core/fieldUtils/root.ts b/packages/deno/packages/core/fieldUtils/root.ts index 85e751a6c..755ff091b 100644 --- a/packages/deno/packages/core/fieldUtils/root.ts +++ b/packages/deno/packages/core/fieldUtils/root.ts @@ -5,6 +5,10 @@ import InputFieldBuilder from './input.ts'; import { ArgBuilder, InputFieldMap, NormalizeArgs } from '../index.ts'; export default class RootFieldBuilder extends BaseFieldUtil { arg: ArgBuilder = new InputFieldBuilder(this.builder, "Arg", this.typename).argBuilder(); + /** + * Create a Boolean field + * @param {GiraphQLSchemaTypes.FieldOptions} options - Options for this field + */ boolean = Types["DefaultFieldNullability"]>(...args: NormalizeArgs<[ options?: Omit, "type"> ]>) { @@ -14,6 +18,10 @@ export default class RootFieldBuilder, ResolveShape, ResolveReturnShape>(...args: NormalizeArgs<[ options?: Omit, "type"> ]>) { @@ -23,18 +31,30 @@ export default class RootFieldBuilder, ResolveShape, ResolveReturnShape>(...args: NormalizeArgs<[ options?: Omit, "type"> ]>) { const [options = {} as never] = args; return this.createField({ ...options, type: "ID" }); } + /** + * Create a Int field + * @param {GiraphQLSchemaTypes.FieldOptions} options - Options for this field + */ int, ResolveShape, ResolveReturnShape>(...args: NormalizeArgs<[ options?: Omit, "type"> ]>) { const [options = {} as never] = args; return this.createField({ ...options, type: "Int" }); } + /** + * Create a String field + * @param {GiraphQLSchemaTypes.FieldOptions} options - Options for this field + */ string = Types["DefaultFieldNullability"]>(...args: NormalizeArgs<[ options?: Omit, "type"> ]>) { @@ -44,6 +64,10 @@ export default class RootFieldBuilder = Types["DefaultFieldNullability"]>(...args: NormalizeArgs<[ @@ -56,6 +80,10 @@ export default class RootFieldBuilder({ ...options, type: ["Boolean"] }); } + /** + * Create a Float list field + * @param {GiraphQLSchemaTypes.FieldOptions} options - Options for this field + */ floatList = Types["DefaultFieldNullability"]>(...args: NormalizeArgs<[ @@ -68,6 +96,10 @@ export default class RootFieldBuilder({ ...options, type: ["Float"] }); } + /** + * Create a ID list field + * @param {GiraphQLSchemaTypes.FieldOptions} options - Options for this field + */ idList, ResolveShape, ResolveReturnShape>(...args: NormalizeArgs<[ @@ -80,6 +112,10 @@ export default class RootFieldBuilder({ ...options, type: ["ID"] }); } + /** + * Create a Int list field + * @param {GiraphQLSchemaTypes.FieldOptions} options - Options for this field + */ intList = Types["DefaultFieldNullability"]>(...args: NormalizeArgs<[ @@ -92,6 +128,10 @@ export default class RootFieldBuilder({ ...options, type: ["Int"] }); } + /** + * Create a String list field + * @param {GiraphQLSchemaTypes.FieldOptions} options - Options for this field + */ stringList = Types["DefaultFieldNullability"]>(...args: NormalizeArgs<[ @@ -104,9 +144,10 @@ export default class RootFieldBuilder({ ...options, type: ["String"] }); } - /** create a new field for the current type - @param {GiraphQLSchemaTypes.FieldOptions} options - options for this field - */ + /** + * create a new field for the current type + * @param {GiraphQLSchemaTypes.FieldOptions} options - options for this field + */ field, ResolveShape, ResolveReturnShape, Nullable extends FieldNullability = Types["DefaultFieldNullability"]>(options: FieldOptionsFromKind) { return this.createField(options); } diff --git a/packages/deno/packages/core/plugins/plugin.ts b/packages/deno/packages/core/plugins/plugin.ts index 3b19981f4..c11f242f7 100644 --- a/packages/deno/packages/core/plugins/plugin.ts +++ b/packages/deno/packages/core/plugins/plugin.ts @@ -15,28 +15,74 @@ export class BasePlugin { this.buildCache = buildCache; this.options = buildCache.options; } + /** + * Called for each type defined with the SchemaBuilder + * @param {GiraphQLTypeConfig} typeConfig - Config object describing the added type + * @return {GiraphQLTypeConfig} Original or updated `typeConfig` + */ onTypeConfig(typeConfig: GiraphQLTypeConfig): GiraphQLTypeConfig { return typeConfig; } + /** + * Called for each field on an Object or Interface type + * @param {GiraphQLOutputFieldConfig} fieldConfig - Config object describing the added field + * @return {GiraphQLOutputFieldConfig} Original or updated `fieldConfig` + */ onOutputFieldConfig(fieldConfig: GiraphQLOutputFieldConfig): GiraphQLOutputFieldConfig | null { return fieldConfig; } + /** + * Called for each argument or field on an Input object defined in your schema + * @param {GiraphQLInputFieldConfig} fieldConfig - Config object describing the added field + * @return {GiraphQLInputFieldConfig} Original or updated `fieldConfig` + */ onInputFieldConfig(fieldConfig: GiraphQLInputFieldConfig): GiraphQLInputFieldConfig | null { return fieldConfig; } + /** + * Called for each Enum value defined in your schema + * @param {GiraphQLEnumValueConfig} valueConfig - Config object describing the enum value + * @return {GiraphQLEnumValueConfig} Original or updated `valueConfig` + */ onEnumValueConfig(valueConfig: GiraphQLEnumValueConfig): GiraphQLEnumValueConfig | null { return valueConfig; } + /** + * Called before builder.toSchema() schema is called + */ beforeBuild() { } + /** + * Called after all fields and types have been built during `builder.toSchema()` + * @param {GraphQLSchema} schema - the generated schema + * @return {GiraphQLEnumValueConfig} Original or updated `schema` + */ afterBuild(schema: GraphQLSchema): GraphQLSchema { return schema; } + /** + * Called with the resolver for each field in the schema + * @param {GraphQLFieldResolver} resolve - the resolve function + * @param {GiraphQLOutputFieldConfig} fieldConfig - the config object for the field associated with this resolve function + * @return {GraphQLFieldResolver} - Either the original, or a new resolver function to use for this field + */ wrapResolve(resolver: GraphQLFieldResolver, fieldConfig: GiraphQLOutputFieldConfig): GraphQLFieldResolver { return resolver; } + /** + * Called with the subscribe for each field on the Subscription type + * @param {GraphQLFieldResolver} subscribe - the subscribe function + * @param {GiraphQLOutputFieldConfig} fieldConfig - the config object for the field associated with this subscribe function + * @return {GraphQLFieldResolver} - Either the original, or a new subscribe function to use for this field + */ wrapSubscribe(subscribe: GraphQLFieldResolver | undefined, fieldConfig: GiraphQLOutputFieldConfig): GraphQLFieldResolver | undefined { return subscribe; } + /** + * Called with the resolveType for each Interface or Union type + * @param {GraphQLTypeResolver} resolveType - the resolveType function + * @param {GiraphQLInterfaceTypeConfig | GiraphQLUnionTypeConfig} typeConfig - the config object for the Interface or Union type + * @return {GraphQLTypeResolver} - Either the original, or a new resolveType function to use for this field + */ wrapResolveType(resolveType: GraphQLTypeResolver, typeConfig: GiraphQLInterfaceTypeConfig | GiraphQLUnionTypeConfig): GraphQLTypeResolver { return resolveType; } @@ -49,9 +95,19 @@ export class BasePlugin { runCache.get(this.builder)!.add(key); } } + /** + * Creates a data object unique to the current request for use by this plugin + * @param {Types['Context']} context - the context object for the current request + * @return {object} - The data object for the current request + */ protected createRequestData(context: Types["Context"]): T { throw new Error("createRequestData not implemented"); } + /** + * Returns a data object for the current request. requires `createRequestData` to be implemented + * @param {Types['Context']} context - the context object for the current request + * @return {object} - The data object for the current request + */ protected requestData(context: Types["Context"]): T { if (!this.requestDataMap.has(context)) { this.requestDataMap.set(context, this.createRequestData(context))!; diff --git a/packages/deno/packages/core/types/global/field-options.ts b/packages/deno/packages/core/types/global/field-options.ts index baf1aba9d..a3b4abc6e 100644 --- a/packages/deno/packages/core/types/global/field-options.ts +++ b/packages/deno/packages/core/types/global/field-options.ts @@ -17,64 +17,71 @@ declare global { deprecationReason?: string; /** extensions for this field for use by directives, server plugins or other tools that depend on extensions */ extensions?: GraphQLFieldExtensions>; - /** Resolver function for this field - @param parent - The parent object for the current type - @param {object} args - args object based on the args defined for this field - @param {object} context - the context object for the current query, based on `Context` type provided to the SchemaBuilder - @param {GraphQLResolveInfo} info - info about how this field was queried - */ + /** + * Resolver function for this field + * @param parent - The parent object for the current type + * @param {object} args - args object based on the args defined for this field + * @param {object} context - the context object for the current query, based on `Context` type provided to the SchemaBuilder + * @param {GraphQLResolveInfo} info - info about how this field was queried + */ resolve?: Resolver, Types["Context"], ShapeFromTypeParam, ResolveReturnShape>; } export interface ObjectFieldOptions, Nullable extends FieldNullability, Args extends InputFieldMap, ResolveReturnShape> extends FieldOptions { - /** Resolver function for this field - @param parent - The parent object for the current type - @param {object} args - args object based on the args defined for this field - @param {object} context - the context object for the current query, based on `Context` type provided to the SchemaBuilder - @param {GraphQLResolveInfo} info - info about how this field was queried - */ + /** + * Resolver function for this field + * @param parent - The parent object for the current type + * @param {object} args - args object based on the args defined for this field + * @param {object} context - the context object for the current query, based on `Context` type provided to the SchemaBuilder + * @param {GraphQLResolveInfo} info - info about how this field was queried + */ resolve: Resolver, Types["Context"], ShapeFromTypeParam, ResolveReturnShape>; } export interface QueryFieldOptions, Nullable extends FieldNullability, Args extends InputFieldMap, ResolveReturnShape> extends FieldOptions { - /** Resolver function for this field - @param root - The root object for this request - @param {object} args - args object based on the args defined for this field - @param {object} context - the context object for the current query, based on `Context` type provided to the SchemaBuilder - @param {GraphQLResolveInfo} info - info about how this field was queried - */ + /** + * Resolver function for this field + * @param root - The root object for this request + * @param {object} args - args object based on the args defined for this field + * @param {object} context - the context object for the current query, based on `Context` type provided to the SchemaBuilder + * @param {GraphQLResolveInfo} info - info about how this field was queried + */ resolve: Resolver, Types["Context"], ShapeFromTypeParam, ResolveReturnShape>; } export interface MutationFieldOptions, Nullable extends FieldNullability, Args extends InputFieldMap, ResolveReturnShape> extends FieldOptions { - /** Resolver function for this field - @param root - The root object for this request - @param {object} args - args object based on the args defined for this field - @param {object} context - the context object for the current query, based on `Context` type provided to the SchemaBuilder - @param {GraphQLResolveInfo} info - info about how this field was queried - */ + /** + * Resolver function for this field + * @param root - The root object for this request + * @param {object} args - args object based on the args defined for this field + * @param {object} context - the context object for the current query, based on `Context` type provided to the SchemaBuilder + * @param {GraphQLResolveInfo} info - info about how this field was queried + */ resolve: Resolver, Types["Context"], ShapeFromTypeParam, ResolveReturnShape>; } export interface InterfaceFieldOptions, Nullable extends FieldNullability, Args extends InputFieldMap, ResolveReturnShape> extends FieldOptions { - /** Resolver function for this field - @param root - The root object for this request - @param {object} args - args object based on the args defined for this field - @param {object} context - the context object for the current query, based on `Context` type provided to the SchemaBuilder - @param {GraphQLResolveInfo} info - info about how this field was queried - */ + /** + * Resolver function for this field + * @param root - The root object for this request + * @param {object} args - args object based on the args defined for this field + * @param {object} context - the context object for the current query, based on `Context` type provided to the SchemaBuilder + * @param {GraphQLResolveInfo} info - info about how this field was queried + */ resolve?: Resolver, Types["Context"], ShapeFromTypeParam, ResolveReturnShape>; } export interface SubscriptionFieldOptions, Nullable extends FieldNullability, Args extends InputFieldMap, ResolveShape, ResolveReturnShape> extends FieldOptions { - /** Resolver function for this field - @param parent - The parent object for this subscription (yielded by subscribe) - @param {object} args - args object based on the args defined for this field - @param {object} context - the context object for the current query, based on `Context` type provided to the SchemaBuilder - @param {GraphQLResolveInfo} info - info about how this field was queried - */ + /** + * Resolver function for this field + * @param parent - The parent object for this subscription (yielded by subscribe) + * @param {object} args - args object based on the args defined for this field + * @param {object} context - the context object for the current query, based on `Context` type provided to the SchemaBuilder + * @param {GraphQLResolveInfo} info - info about how this field was queried + */ resolve: Resolver, Types["Context"], ShapeFromTypeParam, ResolveReturnShape>; - /** Resolver function for this field - @param root - The root object for this request - @param {object} args - args object based on the args defined for this field - @param {object} context - the context object for the current query, based on `Context` type provided to the SchemaBuilder - @param {GraphQLResolveInfo} info - info about how this field was queried - */ + /** + * Resolver function for this field + * @param root - The root object for this request + * @param {object} args - args object based on the args defined for this field + * @param {object} context - the context object for the current query, based on `Context` type provided to the SchemaBuilder + * @param {GraphQLResolveInfo} info - info about how this field was queried + */ subscribe: Subscriber, Types["Context"], ResolveShape>; } export interface FieldOptionsByKind, Nullable extends FieldNullability, Args extends InputFieldMap, ResolveShape, ResolveReturnShape> { @@ -95,7 +102,7 @@ declare global { description?: string; /** When present marks this field as deprecated */ deprecationReason?: string; - /** determins if this field can be omitted (or set as null) */ + /** etermins if this field can be omitted (or set as null) */ required?: Req; /** default value if this field is not included in the query */ defaultValue?: NonNullable>; diff --git a/packages/deno/packages/core/utils/index.ts b/packages/deno/packages/core/utils/index.ts index fb1c4b99a..fd5c07327 100644 --- a/packages/deno/packages/core/utils/index.ts +++ b/packages/deno/packages/core/utils/index.ts @@ -3,6 +3,7 @@ export * from './context-cache.ts'; export * from './enums.ts'; export * from './input.ts'; export * from './params.ts'; +export * from './sort-classes.ts'; export function assertNever(value: never): never { throw new TypeError(`Unexpected value: ${value}`); } diff --git a/packages/deno/packages/core/utils/sort-classes.ts b/packages/deno/packages/core/utils/sort-classes.ts new file mode 100644 index 000000000..bb887f73c --- /dev/null +++ b/packages/deno/packages/core/utils/sort-classes.ts @@ -0,0 +1,21 @@ +// @ts-nocheck +export function classDepth(obj: {}): number { + const proto = Object.getPrototypeOf(obj) as {} | null; + if (!proto) { + return 0; + } + return 1 + classDepth(proto); +} +export function sortClasses unknown>(classes: T[]) { + return [...classes].sort((a, b) => { + const depthA = classDepth(a); + const depthB = classDepth(b); + if (depthA > depthB) { + return -1; + } + if (depthB > depthA) { + return 1; + } + return 0; + }); +} diff --git a/packages/deno/packages/plugin-errors/LICENSE b/packages/deno/packages/plugin-errors/LICENSE new file mode 100644 index 000000000..4d74f2bcf --- /dev/null +++ b/packages/deno/packages/plugin-errors/LICENSE @@ -0,0 +1,6 @@ +ISC License (ISC) +Copyright 2021 Michael Hayes + +Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/packages/deno/packages/plugin-errors/README.md b/packages/deno/packages/plugin-errors/README.md new file mode 100644 index 000000000..5c96e1bce --- /dev/null +++ b/packages/deno/packages/plugin-errors/README.md @@ -0,0 +1,196 @@ +# Errors Plugin + +A plugin for easily including errors in your GraphQL schema. + +## Usage + +### Install + +```bash +yarn add @giraphql/plugin-errors +``` + +### Example Ussage + +```typescript +import ErrorsPlugin from '@giraphql/plugin-errors'; +const builder = new SchemaBuilder({ + plugins: [ErrorsPlugin], + errorOptions: { + defaultTypes: [], + }, +}); + +builder.objectType(Error, { + name: 'Error', + fields: (t) => ({ + message: t.exposeString('message'), + }), +}); + +builder.queryType({ + fields: (t) => ({ + hello: t.string({ + errors: { + type: [Error], + }, + args: { + name: t.arg.string({ required: false }), + }, + resolve: (parent, { name }) => { + if (name.slice(0, 1) !== name.slice(0, 1).toUpperCase()) { + throw new Error('name must be capitalized'); + } + + return `hello, ${name || 'World'}`; + }, + }), + }), +}); +``` + +The above example will produce a GraphQL schema that looks like: + +```graphql +type Error { + message: String! +} + +type Query { + hello(name: String!): QueryHelloResult +} + +union QueryExtendedErrorListOrError = Error | QueryHelloSuccess + +type QueryHelloSuccess { + data: String! +} +``` + +This field can be queried using fragments like: + +```graphql +query { + hello(name: "World") { + __typename + ... on Error { + message + } + ... on QueryHelloSuccess { + data + } + } +} +``` + +This plugin works by wrapping fields that define error options in a union type. This union consists +of an object type for each error type defined for the field, and a Success object type that wraps +the returned data. If the fields resolver throws an instance of one of the defined errors, the +errors plugin will automatically resolve to the corresponding error object type. + +### Builder options + +- `defaultTypes`: An array of Error classes to include in every field with error handling. + +### Options on Fields + +- `types`: An array of Error classes to catch and handle as error objects in the schema. Will be + merged with `defaultTypes` from builder. +- `union`: An options object for the union type. Can include any normal union type options, and + `name` option for setting a custom name for the union type. +- `result`: An options object for result object type. Can include any normal object type options, + and `name` option for setting a custom name for the result type. +- `dataField`: An options object for the data field on the result object. This field will be named + `data` by default, but can be written by passsing a custom `name` option. + +### Recommended Ussage + +1. Set up an Error interface +2. Create a BaseError object type +3. Include the Error interface in any custom Error types you define +4. Include the BaseError type in the `defaultTypes` in the builder config + +This pattern will allow you to consistently query your schema using a `... on Error { message }` +fragment since all Error classes extend that interface. If your client want's to query details of +more specialized error types, they can just add a fragment for the errors it cares about. This +pattern should also make it easier to make future changes without unexpected breaking changes for +your clients. + +The follow is a small example of this pattern: + +```typescript +import ErrorsPlugin from '@giraphql/plugin-errors'; +const builder = new SchemaBuilder({ + plugins: [ErrorsPlugin], + errorOptions: { + defaultTypes: [Error], + }, +}); + +const ErrorInterface = builder.interfaceRef('Error').implement({ + fields: (t) => ({ + message: t.exposeString('message'), + }), +}); + +builder.objectType(Error, { + name: 'BaseError', + isTypeOf: (obj) => obj instanceof Error, + interfaces: [ErrorInterface], +}); + +class LengthError extends Error { + minLength: number; + + constructor(minLength: number) { + super(`string length should be at least ${minLength}`); + + this.minLength = minLength; + this.name = 'LengthError'; + } +} + +builder.objectType(LengthError, { + name: 'LengthError', + interfaces: [ErrorInterface], + isTypeOf: (obj) => obj instanceof LengthError, + fields: (t) => ({ + minLength: t.exposeInt('minLength'), + }), +}); + +builder.queryType({ + fields: (t) => ({ + // Simple error handling just using base error class + hello: t.string({ + errors: {}, + args: { + name: t.arg.string({ required: true }), + }, + resolve: (parent, { name }) => { + if (!name.startsWith(name.slice(0, 1).toUpperCase())) { + throw new Error('name must be capitalized'); + } + + return `hello, ${name || 'World'}`; + }, + }), + // Handling custom errors + helloWithMinLength: t.string({ + errors: { + types: [LengthError], + }, + args: { + name: t.arg.string({ required: true }), + }, + resolve: (parent, { name }) => { + if (name.length < 5) { + throw new LengthError(5); + } + + return `hello, ${name || 'World'}`; + }, + }), + }), +}); +``` diff --git a/packages/deno/packages/plugin-errors/global-types.ts b/packages/deno/packages/plugin-errors/global-types.ts new file mode 100644 index 000000000..9c3e37d3c --- /dev/null +++ b/packages/deno/packages/plugin-errors/global-types.ts @@ -0,0 +1,18 @@ +// @ts-nocheck +/* eslint-disable @typescript-eslint/no-unused-vars */ +import { FieldNullability, InputFieldMap, SchemaTypes, ShapeFromTypeParam, TypeParam, } from '../core/index.ts'; +import { ErrorFieldOptions, ErrorsPluginOptions } from './types.ts'; +import { GiraphQLErrorsPlugin } from './index.ts'; +declare global { + export namespace GiraphQLSchemaTypes { + export interface Plugins { + errors: GiraphQLErrorsPlugin; + } + export interface SchemaBuilderOptions { + errorOptions?: ErrorsPluginOptions; + } + export interface FieldOptions = TypeParam, Nullable extends FieldNullability = FieldNullability, Args extends InputFieldMap = InputFieldMap, ResolveShape = unknown, ResolveReturnShape = unknown> { + errors?: ErrorFieldOptions, Nullable>; + } + } +} diff --git a/packages/deno/packages/plugin-errors/index.ts b/packages/deno/packages/plugin-errors/index.ts new file mode 100644 index 000000000..1f6583ae4 --- /dev/null +++ b/packages/deno/packages/plugin-errors/index.ts @@ -0,0 +1,88 @@ +// @ts-nocheck +import './global-types.ts'; +import { GraphQLFieldResolver } from 'https://cdn.skypack.dev/graphql?dts'; +import SchemaBuilder, { BasePlugin, GiraphQLOutputFieldConfig, SchemaTypes, sortClasses, } from '../core/index.ts'; +export * from './types.ts'; +const pluginName = "errors"; +export default pluginName; +export function capitalize(s: string) { + return `${s.slice(0, 1).toUpperCase()}${s.slice(1)}`; +} +function createErrorProxy(target: {}): {} { + return new Proxy(target, { + getPrototypeOf(err) { + const proto = Object.getPrototypeOf(err) as {}; + if (!proto) { + return proto; + } + return createErrorProxy(proto); + }, + }); +} +const errorTypeMap = new WeakMap<{}, new (...args: any[]) => Error>(); +export class GiraphQLErrorsPlugin extends BasePlugin { + onOutputFieldConfig(fieldConfig: GiraphQLOutputFieldConfig): GiraphQLOutputFieldConfig | null { + if (!fieldConfig.giraphqlOptions.errors) { + return fieldConfig; + } + const parentTypeName = this.buildCache.getTypeConfig(fieldConfig.parentType).name; + const { types = [], result: { name: resultName = `${parentTypeName}${capitalize(fieldConfig.name)}Success`, fields: resultFieldOptions, ...resultObjectOptions } = {}, union: { name: unionName = `${parentTypeName}${capitalize(fieldConfig.name)}Result`, ...unionOptions } = {}, dataField: { name: dataFieldName = "data", ...dataField } = {}, } = fieldConfig.giraphqlOptions.errors; + const resultObjectRef = this.builder.objectRef(resultName); + resultObjectRef.implement({ + ...resultObjectOptions, + fields: (t) => ({ + ...resultFieldOptions?.(t), + [dataFieldName]: t.field({ + ...dataField, + type: fieldConfig.giraphqlOptions.type, + nullable: fieldConfig.type.kind === "List" + ? { items: fieldConfig.type.type.nullable, list: false } + : false, + resolve: (data) => data as never, + }), + }), + }); + const errorTypes = sortClasses([ + ...new Set([...types, ...(this.builder.options.errorOptions?.defaultTypes ?? [])]), + ]); + const unionType = this.builder.unionType(unionName, { + types: [...errorTypes, resultObjectRef], + resolveType: (obj) => errorTypeMap.get(obj as {}) ?? resultObjectRef, + ...unionOptions, + }); + return { + ...fieldConfig, + extensions: { + ...fieldConfig.extensions, + giraphqlErrors: errorTypes, + }, + type: { + kind: "Union", + ref: unionType, + nullable: fieldConfig.type.nullable, + }, + }; + } + wrapResolve(resolver: GraphQLFieldResolver, fieldConfig: GiraphQLOutputFieldConfig): GraphQLFieldResolver { + const giraphqlErrors = fieldConfig.extensions?.giraphqlErrors as typeof Error[] | undefined; + if (!giraphqlErrors) { + return resolver; + } + return async (...args) => { + try { + return (await resolver(...args)) as never; + } + catch (error: unknown) { + for (const errorType of giraphqlErrors) { + if (error instanceof errorType) { + const result = createErrorProxy(error); + errorTypeMap.set(result, errorType); + return result; + } + } + throw error; + } + }; + } +} +SchemaBuilder.registerPlugin(pluginName, GiraphQLErrorsPlugin); diff --git a/packages/deno/packages/plugin-errors/mod.ts b/packages/deno/packages/plugin-errors/mod.ts new file mode 100644 index 000000000..e911f59d9 --- /dev/null +++ b/packages/deno/packages/plugin-errors/mod.ts @@ -0,0 +1,3 @@ +import Default from './index.ts'; +export * from './index.ts'; +export default Default; diff --git a/packages/deno/packages/plugin-errors/types.ts b/packages/deno/packages/plugin-errors/types.ts new file mode 100644 index 000000000..e3577c744 --- /dev/null +++ b/packages/deno/packages/plugin-errors/types.ts @@ -0,0 +1,24 @@ +// @ts-nocheck +import { FieldNullability, SchemaTypes, TypeParam } from '../core/index.ts'; +export interface ErrorsPluginOptions { + defaultTypes?: (new (...args: any[]) => Error)[]; +} +export interface ErrorFieldOptions, Shape, Nullable extends FieldNullability> { + types?: (new (...args: any[]) => Error)[]; + union?: Omit, "resolveType" | "types"> & { + name?: string; + }; + result?: Omit, "interfaces" | "isTypeOf"> & { + name?: string; + }; + dataField?: GiraphQLSchemaTypes.ObjectFieldOptions & { + name?: string; + }; +} diff --git a/packages/plugin-dataloader/package.json b/packages/plugin-dataloader/package.json index 21eff14dd..fb54ceb2e 100644 --- a/packages/plugin-dataloader/package.json +++ b/packages/plugin-dataloader/package.json @@ -26,8 +26,8 @@ "devDependencies": { "@giraphql/core": "^2.8.0", "@giraphql/plugin-relay": "^2.6.0", - "apollo-server": "^2.25.0", + "apollo-server": "^2.25.2", "dataloader": "^2.0.0", - "graphql-tag": "^2.11.0" + "graphql-tag": "^2.12.5" } } diff --git a/packages/plugin-directives/package.json b/packages/plugin-directives/package.json index 4b84a255b..2f470240a 100644 --- a/packages/plugin-directives/package.json +++ b/packages/plugin-directives/package.json @@ -31,9 +31,9 @@ }, "devDependencies": { "@giraphql/core": "^2.8.0", - "apollo-server": "^2.25.0", - "graphql": ">=15.1.0", + "apollo-server": "^2.25.2", + "graphql": ">=15.5.1", "graphql-rate-limit-directive": "^1.3.0", - "graphql-tag": "^2.11.0" + "graphql-tag": "^2.12.5" } } diff --git a/packages/plugin-errors/LICENSE b/packages/plugin-errors/LICENSE new file mode 100644 index 000000000..4d74f2bcf --- /dev/null +++ b/packages/plugin-errors/LICENSE @@ -0,0 +1,6 @@ +ISC License (ISC) +Copyright 2021 Michael Hayes + +Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/packages/plugin-errors/README.md b/packages/plugin-errors/README.md new file mode 100644 index 000000000..5c96e1bce --- /dev/null +++ b/packages/plugin-errors/README.md @@ -0,0 +1,196 @@ +# Errors Plugin + +A plugin for easily including errors in your GraphQL schema. + +## Usage + +### Install + +```bash +yarn add @giraphql/plugin-errors +``` + +### Example Ussage + +```typescript +import ErrorsPlugin from '@giraphql/plugin-errors'; +const builder = new SchemaBuilder({ + plugins: [ErrorsPlugin], + errorOptions: { + defaultTypes: [], + }, +}); + +builder.objectType(Error, { + name: 'Error', + fields: (t) => ({ + message: t.exposeString('message'), + }), +}); + +builder.queryType({ + fields: (t) => ({ + hello: t.string({ + errors: { + type: [Error], + }, + args: { + name: t.arg.string({ required: false }), + }, + resolve: (parent, { name }) => { + if (name.slice(0, 1) !== name.slice(0, 1).toUpperCase()) { + throw new Error('name must be capitalized'); + } + + return `hello, ${name || 'World'}`; + }, + }), + }), +}); +``` + +The above example will produce a GraphQL schema that looks like: + +```graphql +type Error { + message: String! +} + +type Query { + hello(name: String!): QueryHelloResult +} + +union QueryExtendedErrorListOrError = Error | QueryHelloSuccess + +type QueryHelloSuccess { + data: String! +} +``` + +This field can be queried using fragments like: + +```graphql +query { + hello(name: "World") { + __typename + ... on Error { + message + } + ... on QueryHelloSuccess { + data + } + } +} +``` + +This plugin works by wrapping fields that define error options in a union type. This union consists +of an object type for each error type defined for the field, and a Success object type that wraps +the returned data. If the fields resolver throws an instance of one of the defined errors, the +errors plugin will automatically resolve to the corresponding error object type. + +### Builder options + +- `defaultTypes`: An array of Error classes to include in every field with error handling. + +### Options on Fields + +- `types`: An array of Error classes to catch and handle as error objects in the schema. Will be + merged with `defaultTypes` from builder. +- `union`: An options object for the union type. Can include any normal union type options, and + `name` option for setting a custom name for the union type. +- `result`: An options object for result object type. Can include any normal object type options, + and `name` option for setting a custom name for the result type. +- `dataField`: An options object for the data field on the result object. This field will be named + `data` by default, but can be written by passsing a custom `name` option. + +### Recommended Ussage + +1. Set up an Error interface +2. Create a BaseError object type +3. Include the Error interface in any custom Error types you define +4. Include the BaseError type in the `defaultTypes` in the builder config + +This pattern will allow you to consistently query your schema using a `... on Error { message }` +fragment since all Error classes extend that interface. If your client want's to query details of +more specialized error types, they can just add a fragment for the errors it cares about. This +pattern should also make it easier to make future changes without unexpected breaking changes for +your clients. + +The follow is a small example of this pattern: + +```typescript +import ErrorsPlugin from '@giraphql/plugin-errors'; +const builder = new SchemaBuilder({ + plugins: [ErrorsPlugin], + errorOptions: { + defaultTypes: [Error], + }, +}); + +const ErrorInterface = builder.interfaceRef('Error').implement({ + fields: (t) => ({ + message: t.exposeString('message'), + }), +}); + +builder.objectType(Error, { + name: 'BaseError', + isTypeOf: (obj) => obj instanceof Error, + interfaces: [ErrorInterface], +}); + +class LengthError extends Error { + minLength: number; + + constructor(minLength: number) { + super(`string length should be at least ${minLength}`); + + this.minLength = minLength; + this.name = 'LengthError'; + } +} + +builder.objectType(LengthError, { + name: 'LengthError', + interfaces: [ErrorInterface], + isTypeOf: (obj) => obj instanceof LengthError, + fields: (t) => ({ + minLength: t.exposeInt('minLength'), + }), +}); + +builder.queryType({ + fields: (t) => ({ + // Simple error handling just using base error class + hello: t.string({ + errors: {}, + args: { + name: t.arg.string({ required: true }), + }, + resolve: (parent, { name }) => { + if (!name.startsWith(name.slice(0, 1).toUpperCase())) { + throw new Error('name must be capitalized'); + } + + return `hello, ${name || 'World'}`; + }, + }), + // Handling custom errors + helloWithMinLength: t.string({ + errors: { + types: [LengthError], + }, + args: { + name: t.arg.string({ required: true }), + }, + resolve: (parent, { name }) => { + if (name.length < 5) { + throw new LengthError(5); + } + + return `hello, ${name || 'World'}`; + }, + }), + }), +}); +``` diff --git a/packages/plugin-errors/package.json b/packages/plugin-errors/package.json new file mode 100644 index 000000000..cd8fb0c1b --- /dev/null +++ b/packages/plugin-errors/package.json @@ -0,0 +1,37 @@ +{ + "name": "@giraphql/plugin-errors", + "version": "2.0.0", + "description": "A GiraphQL plugin for adding typed errors into your schema", + "main": "./lib/index.js", + "module": "./esm/index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/hayes/giraphql.git" + }, + "author": "Michael Hayes", + "license": "ISC", + "keywords": [ + "giraphql", + "graphql", + "schema", + "typescript", + "error", + "errors", + "plugin" + ], + "publishConfig": { + "access": "public" + }, + "peerDependencies": { + "graphql": ">=15.1.0" + }, + "devDependencies": { + "@giraphql/core": "^2.8.0", + "apollo-server": "^2.25.2", + "graphql": ">=15.5.1", + "graphql-tag": "^2.12.5" + } +} diff --git a/packages/plugin-errors/src/global-types.ts b/packages/plugin-errors/src/global-types.ts new file mode 100644 index 000000000..6ef2b8447 --- /dev/null +++ b/packages/plugin-errors/src/global-types.ts @@ -0,0 +1,34 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import { + FieldNullability, + InputFieldMap, + SchemaTypes, + ShapeFromTypeParam, + TypeParam, +} from '@giraphql/core'; +import { ErrorFieldOptions, ErrorsPluginOptions } from './types'; +import { GiraphQLErrorsPlugin } from '.'; + +declare global { + export namespace GiraphQLSchemaTypes { + export interface Plugins { + errors: GiraphQLErrorsPlugin; + } + + export interface SchemaBuilderOptions { + errorOptions?: ErrorsPluginOptions; + } + + export interface FieldOptions< + Types extends SchemaTypes = SchemaTypes, + ParentShape = unknown, + Type extends TypeParam = TypeParam, + Nullable extends FieldNullability = FieldNullability, + Args extends InputFieldMap = InputFieldMap, + ResolveShape = unknown, + ResolveReturnShape = unknown, + > { + errors?: ErrorFieldOptions, Nullable>; + } + } +} diff --git a/packages/plugin-errors/src/index.ts b/packages/plugin-errors/src/index.ts new file mode 100644 index 000000000..894aae71c --- /dev/null +++ b/packages/plugin-errors/src/index.ts @@ -0,0 +1,131 @@ +import './global-types'; +import { GraphQLFieldResolver } from 'graphql'; +import SchemaBuilder, { + BasePlugin, + GiraphQLOutputFieldConfig, + SchemaTypes, + sortClasses, +} from '@giraphql/core'; + +export * from './types'; + +const pluginName = 'errors'; + +export default pluginName; + +export function capitalize(s: string) { + return `${s.slice(0, 1).toUpperCase()}${s.slice(1)}`; +} + +function createErrorProxy(target: {}): {} { + return new Proxy(target, { + getPrototypeOf(err) { + const proto = Object.getPrototypeOf(err) as {}; + + if (!proto) { + return proto; + } + + return createErrorProxy(proto); + }, + }); +} + +const errorTypeMap = new WeakMap<{}, new (...args: any[]) => Error>(); + +export class GiraphQLErrorsPlugin extends BasePlugin { + onOutputFieldConfig( + fieldConfig: GiraphQLOutputFieldConfig, + ): GiraphQLOutputFieldConfig | null { + if (!fieldConfig.giraphqlOptions.errors) { + return fieldConfig; + } + + const parentTypeName = this.buildCache.getTypeConfig(fieldConfig.parentType).name; + const { + types = [], + result: { + name: resultName = `${parentTypeName}${capitalize(fieldConfig.name)}Success`, + fields: resultFieldOptions, + ...resultObjectOptions + } = {}, + union: { + name: unionName = `${parentTypeName}${capitalize(fieldConfig.name)}Result`, + ...unionOptions + } = {}, + dataField: { name: dataFieldName = 'data', ...dataField } = {}, + } = fieldConfig.giraphqlOptions.errors; + + const resultObjectRef = this.builder.objectRef(resultName); + + resultObjectRef.implement({ + ...resultObjectOptions, + fields: (t) => ({ + ...resultFieldOptions?.(t), + [dataFieldName]: t.field({ + ...dataField, + type: fieldConfig.giraphqlOptions.type, + nullable: + fieldConfig.type.kind === 'List' + ? { items: fieldConfig.type.type.nullable, list: false } + : false, + resolve: (data) => data as never, + }), + }), + }); + + const errorTypes = sortClasses([ + ...new Set([...types, ...(this.builder.options.errorOptions?.defaultTypes ?? [])]), + ]); + + const unionType = this.builder.unionType(unionName, { + types: [...errorTypes, resultObjectRef], + resolveType: (obj) => errorTypeMap.get(obj as {}) ?? resultObjectRef, + ...unionOptions, + }); + + return { + ...fieldConfig, + extensions: { + ...fieldConfig.extensions, + giraphqlErrors: errorTypes, + }, + type: { + kind: 'Union', + ref: unionType, + nullable: fieldConfig.type.nullable, + }, + }; + } + + wrapResolve( + resolver: GraphQLFieldResolver, + fieldConfig: GiraphQLOutputFieldConfig, + ): GraphQLFieldResolver { + const giraphqlErrors = fieldConfig.extensions?.giraphqlErrors as typeof Error[] | undefined; + + if (!giraphqlErrors) { + return resolver; + } + + return async (...args) => { + try { + return (await resolver(...args)) as never; + } catch (error: unknown) { + for (const errorType of giraphqlErrors) { + if (error instanceof errorType) { + const result = createErrorProxy(error); + + errorTypeMap.set(result, errorType); + + return result; + } + } + + throw error; + } + }; + } +} + +SchemaBuilder.registerPlugin(pluginName, GiraphQLErrorsPlugin); diff --git a/packages/plugin-errors/src/types.ts b/packages/plugin-errors/src/types.ts new file mode 100644 index 000000000..3538d6780 --- /dev/null +++ b/packages/plugin-errors/src/types.ts @@ -0,0 +1,35 @@ +import { FieldNullability, SchemaTypes, TypeParam } from '@giraphql/core'; + +export interface ErrorsPluginOptions { + defaultTypes?: (new (...args: any[]) => Error)[]; +} + +export interface ErrorFieldOptions< + Types extends SchemaTypes, + Type extends TypeParam, + Shape, + Nullable extends FieldNullability, +> { + types?: (new (...args: any[]) => Error)[]; + union?: Omit, 'resolveType' | 'types'> & { + name?: string; + }; + result?: Omit, 'interfaces' | 'isTypeOf'> & { + name?: string; + }; + dataField?: GiraphQLSchemaTypes.ObjectFieldOptions< + Types, + Shape, + Type, + Type extends [unknown] + ? { + list: false; + items: Nullable extends { items: boolean } ? Nullable['items'] : true; + } + : false, + {}, + Shape + > & { + name?: string; + }; +} diff --git a/packages/plugin-errors/tests/__snapshots__/index.test.ts.snap b/packages/plugin-errors/tests/__snapshots__/index.test.ts.snap new file mode 100644 index 000000000..486846b0c --- /dev/null +++ b/packages/plugin-errors/tests/__snapshots__/index.test.ts.snap @@ -0,0 +1,65 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`mocked generates expected schema 1`] = ` +"type BaseError implements Error { + message: String! +} + +interface Error { + message: String! +} + +type Extended2Error implements Error { + code: Int! + message: String! +} + +type ExtendedError implements Error { + code: Int! + message: String! +} + +type LengthError implements Error { + message: String! + minLength: Int! +} + +type Query { + extendedError(throw: String): QueryExtendedErrorResult + extendedErrorList(throw: String): QueryExtendedErrorListResult + hello(name: String!): QueryHelloResult! + helloWithMinLength(name: String!): QueryHelloWithMinLengthResult! + simpleError(throw: Boolean): QuerySimpleErrorResult! +} + +union QueryExtendedErrorListResult = BaseError | Extended2Error | ExtendedError | QueryExtendedErrorListSuccess + +type QueryExtendedErrorListSuccess { + data: [String]! +} + +union QueryExtendedErrorResult = BaseError | Extended2Error | ExtendedError | QueryExtendedErrorSuccess + +type QueryExtendedErrorSuccess { + data: String! +} + +union QueryHelloResult = BaseError | QueryHelloSuccess + +type QueryHelloSuccess { + data: String! +} + +union QueryHelloWithMinLengthResult = BaseError | LengthError | QueryHelloWithMinLengthSuccess + +type QueryHelloWithMinLengthSuccess { + data: String! +} + +union QuerySimpleErrorResult = BaseError | QuerySimpleErrorSuccess + +type QuerySimpleErrorSuccess { + data: String! +} +" +`; diff --git a/packages/plugin-errors/tests/example/builder.ts b/packages/plugin-errors/tests/example/builder.ts new file mode 100644 index 000000000..4aa1cb90b --- /dev/null +++ b/packages/plugin-errors/tests/example/builder.ts @@ -0,0 +1,9 @@ +import SchemaBuilder from '@giraphql/core'; +import ErrorPlugin from '@giraphql/plugin-errors'; + +export default new SchemaBuilder<{}>({ + plugins: [ErrorPlugin], + errorOptions: { + defaultTypes: [Error], + }, +}); diff --git a/packages/plugin-errors/tests/example/schema.ts b/packages/plugin-errors/tests/example/schema.ts new file mode 100644 index 000000000..31464fb70 --- /dev/null +++ b/packages/plugin-errors/tests/example/schema.ts @@ -0,0 +1,197 @@ +import builder from './builder'; + +const ErrorInterface = builder.interfaceRef('Error').implement({ + fields: (t) => ({ + message: t.exposeString('message'), + }), +}); + +builder.objectType(Error, { + name: 'BaseError', + isTypeOf: (obj) => obj instanceof Error, + interfaces: [ErrorInterface], +}); + +class LengthError extends Error { + minLength: number; + + constructor(minLength: number) { + super(`string length should be at least ${minLength}`); + + this.minLength = minLength; + this.name = 'LengthError'; + } +} + +builder.objectType(LengthError, { + name: 'LengthError', + interfaces: [ErrorInterface], + isTypeOf: (obj) => obj instanceof LengthError, + fields: (t) => ({ + minLength: t.exposeInt('minLength'), + }), +}); + +builder.queryType({ + fields: (t) => ({ + // Simple error handling just using base error class + hello: t.string({ + errors: {}, + args: { + name: t.arg.string({ required: true }), + }, + resolve: (parent, { name }) => { + if (!name.startsWith(name.slice(0, 1).toUpperCase())) { + throw new Error('name must be capitalized'); + } + + return `hello, ${name || 'World'}`; + }, + }), + // Handling custom errors + helloWithMinLength: t.string({ + errors: { + types: [LengthError], + }, + args: { + name: t.arg.string({ required: true }), + }, + resolve: (parent, { name }) => { + if (name.length < 5) { + throw new LengthError(5); + } + + return `hello, ${name || 'World'}`; + }, + }), + }), +}); + +class ExtendedError extends Error { + errorCode = 123; + + constructor(message: string) { + super(message); + this.name = 'ExtendedError'; + } +} + +class Extended2Error extends Error { + errorCode = 123; + + constructor(message: string) { + super(message); + this.name = 'Extended2Error'; + } +} + +class OtherError { + message: string; + + constructor(message: string) { + this.message = message; + } +} + +builder.objectType(ExtendedError, { + name: 'ExtendedError', + interfaces: [ErrorInterface], + isTypeOf: (obj) => obj instanceof ExtendedError, + fields: (t) => ({ + message: t.exposeString('message'), + code: t.exposeInt('errorCode'), + }), +}); + +builder.objectType(Extended2Error, { + name: 'Extended2Error', + interfaces: [ErrorInterface], + isTypeOf: (obj) => obj instanceof ExtendedError, + fields: (t) => ({ + message: t.exposeString('message'), + code: t.exposeInt('errorCode'), + }), +}); + +builder.queryFields((t) => ({ + simpleError: t.string({ + args: { + throw: t.arg.boolean(), + }, + errors: { + types: [Error], + }, + resolve: (parent, args) => { + if (args.throw) { + throw new Error('Error from simpleError field'); + } + + return 'ok'; + }, + }), + extendedError: t.string({ + nullable: true, + args: { + throw: t.arg.string(), + }, + errors: { + types: [Extended2Error, Error, ExtendedError], + }, + resolve: (parent, args) => { + if (args.throw === 'other') { + // eslint-disable-next-line @typescript-eslint/no-throw-literal + throw new OtherError('Error from extendedError'); + } + + if (args.throw === 'extended') { + throw new ExtendedError('Error from extendedError'); + } + + if (args.throw === 'extended2') { + throw new Extended2Error('Error from extendedError'); + } + + if (args.throw) { + throw new Error('Error from extendedError'); + } + + return 'ok'; + }, + }), + extendedErrorList: t.stringList({ + nullable: { + items: true, + list: true, + }, + args: { + throw: t.arg.string(), + }, + errors: { + types: [Extended2Error, Error, ExtendedError], + }, + resolve: (parent, args) => { + if (args.throw === 'other') { + // eslint-disable-next-line @typescript-eslint/no-throw-literal + throw new OtherError('Error from extendedError'); + } + + if (args.throw === 'extended') { + throw new ExtendedError('Error from extendedError'); + } + + if (args.throw === 'extended2') { + throw new Extended2Error('Error from extendedError'); + } + + if (args.throw) { + throw new Error('Error from extendedError'); + } + + return ['ok']; + }, + }), +})); + +const schema = builder.toSchema({}); + +export default schema; diff --git a/packages/plugin-errors/tests/example/server.ts b/packages/plugin-errors/tests/example/server.ts new file mode 100644 index 000000000..fa7a76b59 --- /dev/null +++ b/packages/plugin-errors/tests/example/server.ts @@ -0,0 +1,12 @@ +import { ApolloServer } from 'apollo-server'; +import schema from './schema'; + +const server = new ApolloServer({ + schema, +}); + +server + .listen(3000, () => { + console.log('🚀 Server started at http://127.0.0.1:3000'); + }) + .catch(console.error); diff --git a/packages/plugin-errors/tests/index.test.ts b/packages/plugin-errors/tests/index.test.ts new file mode 100644 index 000000000..387a92ad0 --- /dev/null +++ b/packages/plugin-errors/tests/index.test.ts @@ -0,0 +1,124 @@ +import { gql } from 'apollo-server-core'; +import { execute, printSchema } from 'graphql'; +import schema from './example/schema'; + +describe('mocked', () => { + it('generates expected schema', () => { + expect(printSchema(schema)).toMatchSnapshot(); + }); + + it('query some stuff', async () => { + const query = gql` + query { + simpleError { + __typename + ... on QuerySimpleErrorResult { + data + } + ... on Error { + message + } + } + extendedError { + __typename + ... on QueryExtendedErrorResult { + data + } + ... on Error { + message + } + } + + simpleErrorError: simpleError(throw: true) { + __typename + ... on QuerySimpleErrorResult { + data + } + ... on Error { + message + } + } + extendedErrorError: extendedError(throw: "error") { + __typename + ... on QueryExtendedErrorResult { + data + } + ... on Error { + message + } + } + + extendedErrorExtended: extendedError(throw: "extended") { + __typename + ... on QueryExtendedErrorResult { + data + } + ... on Error { + message + } + } + + extendedErrorExtended2: extendedError(throw: "extended2") { + __typename + ... on QueryExtendedErrorResult { + data + } + ... on Error { + message + } + } + + extendedErrorOther: extendedError(throw: "other") { + __typename + ... on QueryExtendedErrorResult { + data + } + ... on Error { + message + } + } + } + `; + + const result = await execute({ + schema, + document: query, + contextValue: {}, + }); + + expect(result).toMatchInlineSnapshot(` + Object { + "data": Object { + "extendedError": Object { + "__typename": "QueryExtendedErrorSuccess", + "data": "ok", + }, + "extendedErrorError": Object { + "__typename": "BaseError", + "message": "Error from extendedError", + }, + "extendedErrorExtended": Object { + "__typename": "ExtendedError", + "message": "Error from extendedError", + }, + "extendedErrorExtended2": Object { + "__typename": "Extended2Error", + "message": "Error from extendedError", + }, + "extendedErrorOther": null, + "simpleError": Object { + "__typename": "QuerySimpleErrorSuccess", + "data": "ok", + }, + "simpleErrorError": Object { + "__typename": "BaseError", + "message": "Error from simpleError field", + }, + }, + "errors": Array [ + [GraphQLError: Unexpected error value: { message: "Error from extendedError" }], + ], + } + `); + }); +}); diff --git a/packages/plugin-example/package.json b/packages/plugin-example/package.json index 6c39c3818..c1b063de0 100644 --- a/packages/plugin-example/package.json +++ b/packages/plugin-example/package.json @@ -28,8 +28,8 @@ }, "devDependencies": { "@giraphql/core": "^2.8.0", - "apollo-server": "^2.25.0", - "graphql": ">=15.1.0", - "graphql-tag": "^2.11.0" + "apollo-server": "^2.25.2", + "graphql": ">=15.5.1", + "graphql-tag": "^2.12.5" } } diff --git a/packages/plugin-mocks/package.json b/packages/plugin-mocks/package.json index 68e218268..cbd008521 100644 --- a/packages/plugin-mocks/package.json +++ b/packages/plugin-mocks/package.json @@ -31,8 +31,8 @@ }, "devDependencies": { "@giraphql/core": "^2.8.0", - "apollo-server": "^2.25.0", - "graphql": ">=15.1.0", - "graphql-tag": "^2.11.0" + "apollo-server": "^2.25.2", + "graphql": ">=15.5.1", + "graphql-tag": "^2.12.5" } } diff --git a/packages/plugin-relay/package.json b/packages/plugin-relay/package.json index 7e5e48ccd..41061e02a 100644 --- a/packages/plugin-relay/package.json +++ b/packages/plugin-relay/package.json @@ -33,8 +33,8 @@ }, "devDependencies": { "@giraphql/core": "^2.8.0", - "apollo-server": "^2.25.0", - "graphql": ">=15.1.0", - "graphql-tag": "^2.11.0" + "apollo-server": "^2.25.2", + "graphql": ">=15.5.1", + "graphql-tag": "^2.12.5" } } diff --git a/packages/plugin-scope-auth/package.json b/packages/plugin-scope-auth/package.json index ec0b5a40b..be8e74d0d 100644 --- a/packages/plugin-scope-auth/package.json +++ b/packages/plugin-scope-auth/package.json @@ -33,8 +33,8 @@ }, "devDependencies": { "@giraphql/core": "^2.8.0", - "apollo-server": "^2.25.0", - "graphql": ">=15.1.0", - "graphql-tag": "^2.11.0" + "apollo-server": "^2.25.2", + "graphql": ">=15.5.1", + "graphql-tag": "^2.12.5" } } diff --git a/packages/plugin-simple-objects/package.json b/packages/plugin-simple-objects/package.json index fa191f343..3ef1d307a 100644 --- a/packages/plugin-simple-objects/package.json +++ b/packages/plugin-simple-objects/package.json @@ -31,8 +31,8 @@ }, "devDependencies": { "@giraphql/core": "^2.8.0", - "apollo-server": "^2.25.0", - "graphql": ">=15.1.0", - "graphql-tag": "^2.11.0" + "apollo-server": "^2.25.2", + "graphql": ">=15.5.1", + "graphql-tag": "^2.12.5" } } diff --git a/packages/plugin-smart-subscriptions/package.json b/packages/plugin-smart-subscriptions/package.json index 2647a2f2b..f95bf510a 100644 --- a/packages/plugin-smart-subscriptions/package.json +++ b/packages/plugin-smart-subscriptions/package.json @@ -31,9 +31,9 @@ }, "devDependencies": { "@giraphql/core": "^2.8.0", - "apollo-server": "^2.25.0", - "graphql": ">=15.1.0", + "apollo-server": "^2.25.2", + "graphql": ">=15.5.1", "graphql-subscriptions": "^1.2.1", - "graphql-tag": "^2.11.0" + "graphql-tag": "^2.12.5" } } diff --git a/packages/plugin-sub-graph/package.json b/packages/plugin-sub-graph/package.json index 504596227..1c8298190 100644 --- a/packages/plugin-sub-graph/package.json +++ b/packages/plugin-sub-graph/package.json @@ -34,8 +34,8 @@ }, "devDependencies": { "@giraphql/core": "^2.8.0", - "apollo-server": "^2.25.0", - "graphql": ">=15.1.0", - "graphql-tag": "^2.11.0" + "apollo-server": "^2.25.2", + "graphql": ">=15.5.1", + "graphql-tag": "^2.12.5" } } diff --git a/packages/plugin-validation/package.json b/packages/plugin-validation/package.json index b8f1d8ac9..ba42e1122 100644 --- a/packages/plugin-validation/package.json +++ b/packages/plugin-validation/package.json @@ -26,8 +26,8 @@ "zod": "*" }, "devDependencies": { - "apollo-server": "^2.25.0", - "graphql-tag": "^2.11.0", - "zod": "^3.1.0" + "apollo-server": "^2.25.2", + "graphql-tag": "^2.12.5", + "zod": "^3.2.0" } } diff --git a/yarn.lock b/yarn.lock index 1bbaa43fa..1bf138a52 100644 --- a/yarn.lock +++ b/yarn.lock @@ -22,11 +22,9 @@ long "^4.0.0" "@apollographql/apollo-tools@^0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@apollographql/apollo-tools/-/apollo-tools-0.5.0.tgz#81aadcabb35eeab6ef7e0d3d6c592a6fe15e66d9" - integrity sha512-7IOZHVaKjBq44StXFJEITl4rxgZCsZFSWogAvIErKR9DYV20rt9bJ2mY5lCn+zghfGrweykjLb9g4TDxLg750w== - dependencies: - apollo-env "^0.10.0" + version "0.5.1" + resolved "https://registry.yarnpkg.com/@apollographql/apollo-tools/-/apollo-tools-0.5.1.tgz#f0baef739ff7e2fafcb8b98ad29f6ac817e53e32" + integrity sha512-ZII+/xUFfb9ezDU2gad114+zScxVFMVlZ91f8fGApMzlS1kkqoyLnC4AJaQ1Ya/X+b63I20B4Gd+eCL8QuB4sA== "@apollographql/graphql-playground-html@1.6.27": version "1.6.27" @@ -1722,9 +1720,9 @@ chalk "^4.0.0" "@josephg/resolvable@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@josephg/resolvable/-/resolvable-1.0.0.tgz#cd75b09cfad18cd945de9221d403203aa07e3d0a" - integrity sha512-OfTtjoqB2doov5aTJxkyAMK8dXoo7CjCUQSYUEtiY34jbWduOGV7+168tmCT8COMsUEd5DMSFg/0iAOPCBTNAQ== + version "1.0.1" + resolved "https://registry.yarnpkg.com/@josephg/resolvable/-/resolvable-1.0.1.tgz#69bc4db754d79e1a2f17a650d3466e038d94a5eb" + integrity sha512-CtzORUwWTTOTqfVtHaKRJ0I1kNQd1bpn3sUh8I3nJDVY+5/M/Oe1DnEWzPQvqq/xPIIkzzzIP7mfCoAjFRvDhg== "@lerna/add@4.0.0": version "4.0.0" @@ -2801,19 +2799,19 @@ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.47.tgz#d7a51db20f0650efec24cd04994f523d93172ed4" integrity sha512-c5ciR06jK8u9BstrmJyO97m+klJrrhCf9u3rLu3DEAJBirxRqSCvDQoYKmxuYwQI5SZChAWu+tq9oVlGRuzPAg== -"@types/express-serve-static-core@4.17.19", "@types/express-serve-static-core@^4.17.18": - version "4.17.19" - resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.19.tgz#00acfc1632e729acac4f1530e9e16f6dd1508a1d" - integrity sha512-DJOSHzX7pCiSElWaGR8kCprwibCB/3yW6vcT8VG3P0SJjnv19gnWG/AZMfM60Xj/YJIp/YCaDHyvzsFVeniARA== +"@types/express-serve-static-core@^4.17.18", "@types/express-serve-static-core@^4.17.21": + version "4.17.21" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.21.tgz#a427278e106bca77b83ad85221eae709a3414d42" + integrity sha512-gwCiEZqW6f7EoR8TTEfalyEhb1zA5jQJnRngr97+3pzMaO1RKoI1w2bw07TK72renMUVWcWS5mLI6rk1NqN0nA== dependencies: "@types/node" "*" "@types/qs" "*" "@types/range-parser" "*" -"@types/express@*", "@types/express@4.17.11": - version "4.17.11" - resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.11.tgz#debe3caa6f8e5fcda96b47bd54e2f40c4ee59545" - integrity sha512-no+R6rW60JEc59977wIxreQVsIEOAYwgCqldrA/vkpCnbD7MqTefO97lmoBe4WE0F156bC4uLSP1XHDOySnChg== +"@types/express@*", "@types/express@^4.17.12": + version "4.17.12" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.12.tgz#4bc1bf3cd0cfe6d3f6f2853648b40db7d54de350" + integrity sha512-pTYas6FrP15B1Oa0bkN5tQMNqOcVXa9j4FTFtO8DWI9kppKib+6NJtfTOOLcwxuuYvcX2+dVG6et1SxW/Kc17Q== dependencies: "@types/body-parser" "*" "@types/express-serve-static-core" "^4.17.18" @@ -2894,9 +2892,9 @@ "@types/koa" "*" "@types/koa@*": - version "2.13.1" - resolved "https://registry.yarnpkg.com/@types/koa/-/koa-2.13.1.tgz#e29877a6b5ad3744ab1024f6ec75b8cbf6ec45db" - integrity sha512-Qbno7FWom9nNqu0yHZ6A0+RWt4mrYBhw3wpBAQ3+IuzGcLlfeYkzZrnMq5wsxulN2np8M4KKeUpTodsOsSad5Q== + version "2.13.3" + resolved "https://registry.yarnpkg.com/@types/koa/-/koa-2.13.3.tgz#5b44c0956d7f7bf41f74ccfb530fec60fbed45ca" + integrity sha512-TaujBV+Dhe/FvmSMZJtCFBms+bqQacgUebk/M2C2tq8iGmHE/DDf4DcW2Hc7NqusVZmy5xzrWOjtdPKNP+fTfw== dependencies: "@types/accepts" "*" "@types/content-disposition" "*" @@ -2935,26 +2933,21 @@ "@types/node" "*" form-data "^3.0.0" -"@types/node@*": - version "15.0.1" - resolved "https://registry.yarnpkg.com/@types/node/-/node-15.0.1.tgz#ef34dea0881028d11398be5bf4e856743e3dc35a" - integrity sha512-TMkXt0Ck1y0KKsGr9gJtWGjttxlZnnvDtphxUOSd0bfaR6Q1jle+sPvrzNR1urqYTWMinoKvjKfXUGsumaO1PA== +"@types/node@*", "@types/node@^15.12.5": + version "15.12.5" + resolved "https://registry.yarnpkg.com/@types/node/-/node-15.12.5.tgz#9a78318a45d75c9523d2396131bd3cca54b2d185" + integrity sha512-se3yX7UHv5Bscf8f1ERKvQOD6sTyycH3hdaoozvaLxgUiY5lIGEeH37AD0G0Qi9kPqihPn0HOfd2yaIEN9VwEg== "@types/node@^10.1.0": - version "10.17.59" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.59.tgz#03f440ccf746a27f7da6e141e6cbae64681dbd2f" - integrity sha512-7Uc8IRrL8yZz5ti45RaFxpbU8TxlzdC3HvxV+hOWo1EyLsuKv/w7y0n+TwZzwL3vdx3oZ2k3ubxPq131hNtXyg== + version "10.17.60" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.60.tgz#35f3d6213daed95da7f0f73e75bcc6980e90597b" + integrity sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw== "@types/node@^14.0.14": version "14.14.43" resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.43.tgz#26bcbb0595b305400e8ceaf9a127a7f905ae49c8" integrity sha512-3pwDJjp1PWacPTpH0LcfhgjvurQvrZFBrC6xxjaUEZ7ifUtT32jtjPxEMMblpqd2Mvx+k8haqQJLQxolyGN/cQ== -"@types/node@^15.12.0": - version "15.12.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-15.12.0.tgz#6a459d261450a300e6865faeddb5af01c3389bb3" - integrity sha512-+aHJvoCsVhO2ZCuT4o5JtcPrCPyDE3+1nvbDprYes+pPkEsbjH7AGUCNtjMOXS0fqH14t+B7yLzaqSz92FPWyw== - "@types/normalize-package-data@^2.4.0": version "2.4.0" resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e" @@ -2994,9 +2987,9 @@ integrity sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw== "@types/ws@^7.0.0": - version "7.4.2" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.2.tgz#bfe739b5f8b3a39742605fbe415ae7e88ee614c8" - integrity sha512-PbeN0Eydl7LQl4OIav29YmkO2LxbVuz3nZD/kb19lOS+wLgIkRbWMNmU/QQR7ABpOJ7D7xDOU8co7iohObewrw== + version "7.4.5" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.5.tgz#8ff0f7efcd8fea19f51f9dd66cb8b498d172a752" + integrity sha512-8mbDgtc8xpxDDem5Gwj76stBDJX35KQ3YBoayxlqUQcL5BZUthiqP/VQ4PQnLHqM4PmlbyO74t98eJpURO+gPA== dependencies: "@types/node" "*" @@ -3282,11 +3275,6 @@ ansi-regex@^5.0.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== -ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= - ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" @@ -3333,20 +3321,10 @@ apollo-datasource@^0.9.0: apollo-server-caching "^0.7.0" apollo-server-env "^3.1.0" -apollo-env@^0.10.0: - version "0.10.0" - resolved "https://registry.yarnpkg.com/apollo-env/-/apollo-env-0.10.0.tgz#8dd51bf974253a760ea15c81e870ff2c0d6e6820" - integrity sha512-7Geot+eyOl4jzPi9beiszeDmEEVZOVT11LSlkQluF5eaCNaIvld+xklZxITZGI/Wr+PQX380YJgQt1ndR2GtOg== - dependencies: - "@types/node-fetch" "^2.5.10" - core-js "^3.0.1" - node-fetch "^2.6.1" - sha.js "^2.4.11" - apollo-graphql@^0.9.0: - version "0.9.2" - resolved "https://registry.yarnpkg.com/apollo-graphql/-/apollo-graphql-0.9.2.tgz#750ca9a97b59c868426defc95d9d9e1733ae4bdf" - integrity sha512-+c/vqC2LPq3e5kO7MfBxDDiljzLog/THZr9Pd46HVaKAhHUxFL0rJEbT17VhjdOoZGWFWLYG7x9hiN6EQD1xZQ== + version "0.9.3" + resolved "https://registry.yarnpkg.com/apollo-graphql/-/apollo-graphql-0.9.3.tgz#1ca6f625322ae10a66f57a39642849a07a7a5dc9" + integrity sha512-rcAl2E841Iko4kSzj4Pt3PRBitmyq1MvoEmpl04TQSpGnoVgl1E/ZXuLBYxMTSnEAm7umn2IsoY+c6Ll9U/10A== dependencies: core-js-pure "^3.10.2" lodash.sortby "^4.7.0" @@ -3376,10 +3354,10 @@ apollo-server-caching@^0.7.0: dependencies: lru-cache "^6.0.0" -apollo-server-core@^2.25.0: - version "2.25.0" - resolved "https://registry.yarnpkg.com/apollo-server-core/-/apollo-server-core-2.25.0.tgz#a0841e57c3605d638809f541dfc87370386b7372" - integrity sha512-LqDmY+R5dcb6zj/RgM7P8NnURV2XdQFIF4rY7g80hD9mc2WSCKHF6eH+lHG0sFPW7f8iBr+lJ4LyETuWEVF0hg== +apollo-server-core@^2.25.2: + version "2.25.2" + resolved "https://registry.yarnpkg.com/apollo-server-core/-/apollo-server-core-2.25.2.tgz#ff65da5e512d9b5ca54c8e5e8c78ee28b5987247" + integrity sha512-lrohEjde2TmmDTO7FlOs8x5QQbAS0Sd3/t0TaK2TWaodfzi92QAvIsq321Mol6p6oEqmjm8POIDHW1EuJd7XMA== dependencies: "@apollographql/apollo-tools" "^0.5.0" "@apollographql/graphql-playground-html" "1.6.27" @@ -3404,9 +3382,8 @@ apollo-server-core@^2.25.0: loglevel "^1.6.7" lru-cache "^6.0.0" sha.js "^2.4.11" - subscriptions-transport-ws "^0.9.11" + subscriptions-transport-ws "^0.9.19" uuid "^8.0.0" - ws "^6.0.0" apollo-server-env@^3.1.0: version "3.1.0" @@ -3421,19 +3398,19 @@ apollo-server-errors@^2.5.0: resolved "https://registry.yarnpkg.com/apollo-server-errors/-/apollo-server-errors-2.5.0.tgz#5d1024117c7496a2979e3e34908b5685fe112b68" integrity sha512-lO5oTjgiC3vlVg2RKr3RiXIIQ5pGXBFxYGGUkKDhTud3jMIhs+gel8L8zsEjKaKxkjHhCQAA/bcEfYiKkGQIvA== -apollo-server-express@^2.25.0: - version "2.25.0" - resolved "https://registry.yarnpkg.com/apollo-server-express/-/apollo-server-express-2.25.0.tgz#0551a23cf47509349ee438cef6bd10d9856ba9f8" - integrity sha512-FCTisD+VB1LCcTjjhKvQZ/dkly83KVlioFMgcPjW1X/kzCznRT3aQoVn9bQHlzQr7NnpwFseb4Rhd2KKD4wKEA== +apollo-server-express@^2.25.2: + version "2.25.2" + resolved "https://registry.yarnpkg.com/apollo-server-express/-/apollo-server-express-2.25.2.tgz#58cd819694ff4c2dec6945a95c5dff6aa2719ef6" + integrity sha512-A2gF2e85vvDugPlajbhr0A14cDFDIGX0mteNOJ8P3Z3cIM0D4hwrWxJidI+SzobefDIyIHu1dynFedJVhV0euQ== dependencies: "@apollographql/graphql-playground-html" "1.6.27" "@types/accepts" "^1.3.5" "@types/body-parser" "1.19.0" "@types/cors" "2.8.10" - "@types/express" "4.17.11" - "@types/express-serve-static-core" "4.17.19" + "@types/express" "^4.17.12" + "@types/express-serve-static-core" "^4.17.21" accepts "^1.3.5" - apollo-server-core "^2.25.0" + apollo-server-core "^2.25.2" apollo-server-types "^0.9.0" body-parser "^1.18.3" cors "^2.8.5" @@ -3441,7 +3418,7 @@ apollo-server-express@^2.25.0: graphql-subscriptions "^1.0.0" graphql-tools "^4.0.8" parseurl "^1.3.2" - subscriptions-transport-ws "^0.9.16" + subscriptions-transport-ws "^0.9.19" type-is "^1.6.16" apollo-server-plugin-base@^0.13.0: @@ -3460,13 +3437,13 @@ apollo-server-types@^0.9.0: apollo-server-caching "^0.7.0" apollo-server-env "^3.1.0" -apollo-server@^2.25.0: - version "2.25.0" - resolved "https://registry.yarnpkg.com/apollo-server/-/apollo-server-2.25.0.tgz#2b76dca152b82f978ae2f634103164a8ac13df65" - integrity sha512-cIXrEWzYWH2y4P4HrfTS0ql6UfJuPO1czb5u9Ch8bLPcWcL1lC84ZbsHzQHNNMLkNApSCAgoS3GZja7dF111Hw== +apollo-server@^2.25.2: + version "2.25.2" + resolved "https://registry.yarnpkg.com/apollo-server/-/apollo-server-2.25.2.tgz#db45c3ef8d9116cee8f12218f06588db717fee9e" + integrity sha512-2Ekx9puU5DqviZk6Kw1hbqTun3lwOWUjhiBJf+UfifYmnqq0s9vAv6Ditw+DEXwphJQ4vGKVVgVIEw6f/9YfhQ== dependencies: - apollo-server-core "^2.25.0" - apollo-server-express "^2.25.0" + apollo-server-core "^2.25.2" + apollo-server-express "^2.25.2" express "^4.0.0" graphql-subscriptions "^1.0.0" graphql-tools "^4.0.8" @@ -3603,7 +3580,7 @@ array.prototype.flatmap@^1.2.4: es-abstract "^1.18.0-next.1" function-bind "^1.1.1" -arrify@^1.0.0, arrify@^1.0.1: +arrify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= @@ -3660,11 +3637,6 @@ async-each@^1.0.1: resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== -async-limiter@~1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" - integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== - async-retry@^1.2.1: version "1.3.1" resolved "https://registry.yarnpkg.com/async-retry/-/async-retry-1.3.1.tgz#139f31f8ddce50c0870b0ba558a6079684aaed55" @@ -4097,17 +4069,6 @@ caseless@~0.12.0: resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= -chalk@^1.1.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= - dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" - chalk@^2.0.0, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -4575,12 +4536,17 @@ core-js-compat@^3.9.0, core-js-compat@^3.9.1: browserslist "^4.16.5" semver "7.0.0" -core-js-pure@^3.0.0, core-js-pure@^3.10.2: +core-js-pure@^3.0.0: version "3.11.1" resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.11.1.tgz#fd52fa8c8b7b797b3606524b3d97278a8d8e7f09" integrity sha512-2JukQi8HgAOCD5CSimxWWXVrUBoA9Br796uIA5Z06bIjt7PBBI19ircFaAxplgE1mJf3x2BY6MkT/HWA/UryPg== -core-js@^3.0.1, core-js@^3.6.5: +core-js-pure@^3.10.2: + version "3.15.1" + resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.15.1.tgz#8356f6576fa2aa8e54ca6fe02620968ff010eed7" + integrity sha512-OZuWHDlYcIda8sJLY4Ec6nWq2hRjlyCqCZ+jCflyleMkVt3tPedDVErvHslyS2nbO+SlBFMSBJYvtLMwxnrzjA== + +core-js@^3.6.5: version "3.11.1" resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.11.1.tgz#f920392bf8ed63a0ec8e4e729857bfa3d121c525" integrity sha512-k93Isqg7e4txZWMGNYwevZL9MiogLk8pd1PtwrmFmi8IBq4GXqUaVW/a33Llt6amSI36uSjd0GWwc9pTT9ALlQ== @@ -4857,11 +4823,6 @@ diff-sequences@^26.6.2: resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.6.2.tgz#48ba99157de1923412eed41db6b6d4aa9ca7c0b1" integrity sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q== -diff@^3.1.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" - integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== - diff@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" @@ -5017,7 +4978,7 @@ error-ex@^1.2.0, error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -es-abstract@^1.18.0-next.1, es-abstract@^1.18.0-next.2: +es-abstract@^1.18.0-next.1: version "1.18.0" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.0.tgz#ab80b359eecb7ede4c298000390bc5ac3ec7b5a4" integrity sha512-LJzK7MrQa8TS0ja2w3YNLzUgJCGPdPOV1yVvezjNnS89D+VR08+Szt2mz3YB2Dck/+w5tfIq/RoUAFqJJGM2yw== @@ -5039,6 +5000,28 @@ es-abstract@^1.18.0-next.1, es-abstract@^1.18.0-next.2: string.prototype.trimstart "^1.0.4" unbox-primitive "^1.0.0" +es-abstract@^1.18.0-next.2: + version "1.18.3" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.3.tgz#25c4c3380a27aa203c44b2b685bba94da31b63e0" + integrity sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw== + dependencies: + call-bind "^1.0.2" + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + get-intrinsic "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.2" + is-callable "^1.2.3" + is-negative-zero "^2.0.1" + is-regex "^1.1.3" + is-string "^1.0.6" + object-inspect "^1.10.3" + object-keys "^1.1.1" + object.assign "^4.1.2" + string.prototype.trimend "^1.0.4" + string.prototype.trimstart "^1.0.4" + unbox-primitive "^1.0.1" + es-to-primitive@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" @@ -5058,7 +5041,7 @@ escape-html@~1.0.3: resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= -escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: +escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= @@ -5764,10 +5747,10 @@ form-data@~2.3.2: combined-stream "^1.0.6" mime-types "^2.1.12" -forwarded@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" - integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== fragment-cache@^0.2.1: version "0.2.1" @@ -6069,10 +6052,10 @@ graphql-rate-limit-directive@^1.3.0: graphql-tag "^2.12.0" rate-limiter-flexible "^2.0.0" -graphql-scalars@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/graphql-scalars/-/graphql-scalars-1.9.3.tgz#84d27e42d280a16821ab0ef59cddaac84f798575" - integrity sha512-vP71Og4ALfe3PCk6T+B7LcJHH55gL0tYidmAE/kWT3ScE2FUCFS7iiMXFQXjCaYLi8nZcRLn9HuejGcjZ8kRug== +graphql-scalars@^1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/graphql-scalars/-/graphql-scalars-1.10.0.tgz#9daf9252b16e6fae553a06976163a23f41b65dfd" + integrity sha512-LONlj8FfhA2iGpkZJWf5e4PVAHXxnZEHSOEvowLYvNXl/TNnhIck8VmE+lren/aa6GKrG+lZufo5lgnyjxcF6g== dependencies: tslib "~2.2.0" @@ -6083,7 +6066,14 @@ graphql-subscriptions@^1.0.0, graphql-subscriptions@^1.2.1: dependencies: iterall "^1.3.0" -graphql-tag@^2.11.0, graphql-tag@^2.12.0: +graphql-tag@^2.11.0, graphql-tag@^2.12.5: + version "2.12.5" + resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.12.5.tgz#5cff974a67b417747d05c8d9f5f3cb4495d0db8f" + integrity sha512-5xNhP4063d16Pz3HBtKprutsPrmHZi5IdUGOWRxA2B6VF7BIRGOHZ5WQvDmJXZuPcBg7rYwaFxvQYjqkSdR3TQ== + dependencies: + tslib "^2.1.0" + +graphql-tag@^2.12.0: version "2.12.4" resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.12.4.tgz#d34066688a4f09e72d6f4663c74211e9b4b7c4bf" integrity sha512-VV1U4O+9x99EkNpNmCUV5RZwq6MnK4+pGbRYWG+lA/m3uo7TSqJF81OkcOP148gFP6fzdl7JWYBrwWVTS9jXww== @@ -6101,10 +6091,10 @@ graphql-tools@^4.0.8: iterall "^1.1.3" uuid "^3.1.0" -graphql@15.5.0, graphql@>=15.1.0, graphql@^15.0.0, graphql@^15.5.0: - version "15.5.0" - resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.5.0.tgz#39d19494dbe69d1ea719915b578bf920344a69d5" - integrity sha512-OmaM7y0kaK31NKG31q4YbD2beNYa6jBBKtMFT6gLYJljHLJr42IqJ8KX08u3Li/0ifzTU5HjmoOOrwa5BRLeDA== +graphql@>=15.5.1, graphql@^15.0.0, graphql@^15.5.1: + version "15.5.1" + resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.5.1.tgz#f2f84415d8985e7b84731e7f3536f8bb9d383aad" + integrity sha512-FeTRX67T3LoE3LWAxxOlW2K3Bz+rMYAC18rRguK4wgXaTZMiJwSUwDmPFo3UadAKbzirKIg5Qy+sNJXbpPRnQw== growly@^1.3.0: version "1.3.0" @@ -6141,13 +6131,6 @@ hard-rejection@^2.1.0: resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883" integrity sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA== -has-ansi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= - dependencies: - ansi-regex "^2.0.0" - has-bigints@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" @@ -6566,9 +6549,9 @@ is-arrayish@^0.2.1: integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= is-bigint@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.1.tgz#6923051dfcbc764278540b9ce0e6b3213aa5ebc2" - integrity sha512-J0ELF4yHFxHy0cmSxZuheDOz2luOdVvqjwmEcj8H/L1JHeuEDSDbeRP+Dk9kFVk5RTFzbucJ2Kb9F7ixY2QaCg== + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.2.tgz#ffb381442503235ad245ea89e45b3dbff040ee5a" + integrity sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA== is-binary-path@^1.0.0: version "1.0.1" @@ -6585,11 +6568,11 @@ is-binary-path@~2.1.0: binary-extensions "^2.0.0" is-boolean-object@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.0.tgz#e2aaad3a3a8fca34c28f6eee135b156ed2587ff0" - integrity sha512-a7Uprx8UtD+HWdyYwnD1+ExtTgqQtD2k/1yJgtXP6wnMm8byhkoTZRl+95LLThpzNZJ5aEvi46cdH+ayMFRwmA== + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.1.tgz#3c0878f035cb821228d350d2e1e36719716a3de8" + integrity sha512-bXdQWkECBUIAcCkeH1unwJLIpZYaa5VvuygSyS/c2lf719mTKZDU5UdDRlpd01UjADgmW8RfqaP+mRaVPdr/Ng== dependencies: - call-bind "^1.0.0" + call-bind "^1.0.2" is-buffer@^1.1.5: version "1.1.6" @@ -6637,9 +6620,9 @@ is-data-descriptor@^1.0.0: kind-of "^6.0.0" is-date-object@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" - integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.4.tgz#550cfcc03afada05eea3dd30981c7b09551f73e5" + integrity sha512-/b4ZVsG7Z5XVtIxs/h9W8nvfLgSAyKYdtGWQLbqy6jA1icmgjf8WCoTKgeS4wy5tYaPePouzFMANbnj94c2Z+A== is-descriptor@^0.1.0: version "0.1.6" @@ -6740,9 +6723,9 @@ is-negative-zero@^2.0.1: integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w== is-number-object@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.4.tgz#36ac95e741cf18b283fc1ddf5e83da798e3ec197" - integrity sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw== + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.5.tgz#6edfaeed7950cff19afedce9fbfca9ee6dd289eb" + integrity sha512-RU0lI/n95pMoUKu9v1BZP5MBcZuNSVJkMkAG2dJqC4z2GlkGUNeH68SuHuBKBD/XFe+LHZ+f9BKkLET60Niedw== is-number@^3.0.0: version "3.0.0" @@ -6793,13 +6776,13 @@ is-potential-custom-element-name@^1.0.0: resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== -is-regex@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.2.tgz#81c8ebde4db142f2cf1c53fc86d6a45788266251" - integrity sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg== +is-regex@^1.1.2, is-regex@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.3.tgz#d029f9aff6448b93ebbe3f33dac71511fdcbef9f" + integrity sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ== dependencies: call-bind "^1.0.2" - has-symbols "^1.0.1" + has-symbols "^1.0.2" is-regexp@^1.0.0: version "1.0.0" @@ -6823,17 +6806,17 @@ is-stream@^2.0.0: resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3" integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw== -is-string@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6" - integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ== +is-string@^1.0.5, is-string@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.6.tgz#3fe5d5992fb0d93404f32584d4b0179a71b54a5f" + integrity sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w== is-symbol@^1.0.2, is-symbol@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" - integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ== + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== dependencies: - has-symbols "^1.0.1" + has-symbols "^1.0.2" is-text-path@^1.0.1: version "1.0.1" @@ -8030,13 +8013,25 @@ mime-db@1.47.0: resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.47.0.tgz#8cb313e59965d3c05cfbf898915a267af46a335c" integrity sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw== -mime-types@^2.1.12, mime-types@~2.1.19, mime-types@~2.1.24: +mime-db@1.48.0: + version "1.48.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.48.0.tgz#e35b31045dd7eada3aaad537ed88a33afbef2d1d" + integrity sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ== + +mime-types@^2.1.12, mime-types@~2.1.19: version "2.1.30" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.30.tgz#6e7be8b4c479825f85ed6326695db73f9305d62d" integrity sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg== dependencies: mime-db "1.47.0" +mime-types@~2.1.24: + version "2.1.31" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.31.tgz#a00d76b74317c61f9c2db2218b8e9f8e9c5c9e6b" + integrity sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg== + dependencies: + mime-db "1.48.0" + mime@1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" @@ -8536,10 +8531,10 @@ object-copy@^0.1.0: define-property "^0.2.5" kind-of "^3.0.3" -object-inspect@^1.9.0: - version "1.10.2" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.10.2.tgz#b6385a3e2b7cae0b5eafcf90cddf85d128767f30" - integrity sha512-gz58rdPpadwztRrPjZE9DZLOABUpTGdcANUgOwBFO1C+HZZhePoP83M65WGDmbpwFYJSWqavbl4SgDn4k8RYTA== +object-inspect@^1.10.3, object-inspect@^1.9.0: + version "1.10.3" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.10.3.tgz#c2aa7d2d09f50c99375704f7a0adf24c5782d369" + integrity sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw== object-keys@^1.0.12, object-keys@^1.1.1: version "1.1.1" @@ -9047,7 +9042,7 @@ pinkie-promise@^2.0.0: dependencies: pinkie "^2.0.0" -pinkie@^2.0.0, pinkie@^2.0.4: +pinkie@^2.0.0: version "2.0.4" resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= @@ -9192,11 +9187,11 @@ protocols@^1.1.0, protocols@^1.4.0: integrity sha512-IgjKyaUSjsROSO8/D49Ab7hP8mJgTYcqApOqdPhLoPxAplXmkp+zRvsrSQjFn5by0rhm4VH0GAUELIPpx7B1yg== proxy-addr@~2.0.5: - version "2.0.6" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf" - integrity sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw== + version "2.0.7" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== dependencies: - forwarded "~0.1.2" + forwarded "0.2.0" ipaddr.js "1.9.1" psl@^1.1.28, psl@^1.1.33: @@ -10135,13 +10130,6 @@ source-map-resolve@^0.5.0: source-map-url "^0.4.0" urix "^0.1.0" -source-map-support@^0.4.0: - version "0.4.18" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" - integrity sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA== - dependencies: - source-map "^0.5.6" - source-map-support@^0.5.17, source-map-support@^0.5.6: version "0.5.19" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" @@ -10457,11 +10445,6 @@ strip-indent@^3.0.0: dependencies: min-indent "^1.0.0" -strip-json-comments@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= - strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" @@ -10476,21 +10459,16 @@ strong-log-transformer@^2.1.0: minimist "^1.2.0" through "^2.3.4" -subscriptions-transport-ws@^0.9.11, subscriptions-transport-ws@^0.9.16: - version "0.9.18" - resolved "https://registry.yarnpkg.com/subscriptions-transport-ws/-/subscriptions-transport-ws-0.9.18.tgz#bcf02320c911fbadb054f7f928e51c6041a37b97" - integrity sha512-tztzcBTNoEbuErsVQpTN2xUNN/efAZXyCyL5m3x4t6SKrEiTL2N8SaKWBFWM4u56pL79ULif3zjyeq+oV+nOaA== +subscriptions-transport-ws@^0.9.19: + version "0.9.19" + resolved "https://registry.yarnpkg.com/subscriptions-transport-ws/-/subscriptions-transport-ws-0.9.19.tgz#10ca32f7e291d5ee8eb728b9c02e43c52606cdcf" + integrity sha512-dxdemxFFB0ppCLg10FTtRqH/31FNRL1y1BQv8209MK5I4CwALb7iihQg+7p65lFcIl8MHatINWBLOqpgU4Kyyw== dependencies: backo2 "^1.0.2" eventemitter3 "^3.1.0" iterall "^1.2.1" symbol-observable "^1.0.4" - ws "^5.2.0" - -supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= + ws "^5.2.0 || ^6.0.0 || ^7.0.0" supports-color@^5.3.0: version "5.5.0" @@ -10774,24 +10752,6 @@ ts-node@^10.0.0: source-map-support "^0.5.17" yn "3.1.1" -ts-node@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-2.1.2.tgz#45087b45e7b371b3daf04ecc470ec29a836655ea" - integrity sha1-RQh7ReezcbPa8E7MRw7CmoNmVeo= - dependencies: - arrify "^1.0.0" - chalk "^1.1.1" - diff "^3.1.0" - make-error "^1.1.1" - minimist "^1.2.0" - mkdirp "^0.5.1" - pinkie "^2.0.4" - source-map-support "^0.4.0" - tsconfig "^6.0.0" - v8flags "^2.0.11" - xtend "^4.0.0" - yn "^1.2.0" - tsconfig-beemo@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/tsconfig-beemo/-/tsconfig-beemo-0.1.2.tgz#de05f245ed919b0b5ad8ce828720f93fa41705e9" @@ -10807,24 +10767,21 @@ tsconfig-paths@^3.9.0: minimist "^1.2.0" strip-bom "^3.0.0" -tsconfig@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/tsconfig/-/tsconfig-6.0.0.tgz#6b0e8376003d7af1864f8df8f89dd0059ffcd032" - integrity sha1-aw6DdgA9evGGT434+J3QBZ/80DI= - dependencies: - strip-bom "^3.0.0" - strip-json-comments "^2.0.0" - tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.0.3, tslib@^2.1.0, tslib@~2.2.0: +tslib@^2.0.3, tslib@~2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.2.0.tgz#fb2c475977e35e241311ede2693cee1ec6698f5c" integrity sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w== +tslib@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e" + integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg== + tslib@~2.0.1: version "2.0.3" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.3.tgz#8e0741ac45fc0c226e58a17bfc3e64b9bc6ca61c" @@ -10943,7 +10900,7 @@ umask@^1.1.0: resolved "https://registry.yarnpkg.com/umask/-/umask-1.1.0.tgz#f29cebf01df517912bb58ff9c4e50fde8e33320d" integrity sha1-8pzr8B31F5ErtY/5xOUP3o4zMg0= -unbox-primitive@^1.0.0: +unbox-primitive@^1.0.0, unbox-primitive@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw== @@ -11067,11 +11024,6 @@ use@^3.1.0: resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== -user-home@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" - integrity sha1-K1viOjK2Onyd640PKNSFcko98ZA= - util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" @@ -11124,13 +11076,6 @@ v8-to-istanbul@^7.0.0: convert-source-map "^1.6.0" source-map "^0.7.3" -v8flags@^2.0.11: - version "2.1.1" - resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.1.1.tgz#aab1a1fa30d45f88dd321148875ac02c0b55e5b4" - integrity sha1-qrGh+jDUX4jdMhFIh1rALAtV5bQ= - dependencies: - user-home "^1.1.1" - validate-npm-package-license@^3.0.1, validate-npm-package-license@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" @@ -11353,19 +11298,10 @@ write-pkg@^4.0.0: type-fest "^0.4.1" write-json-file "^3.2.0" -ws@^5.2.0: - version "5.2.3" - resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.3.tgz#05541053414921bc29c63bee14b8b0dd50b07b3d" - integrity sha512-jZArVERrMsKUatIdnLzqvcfydI85dvd/Fp1u/VOpfdDWQ4c9qWXe+VIeAbQ5FrDwciAkr+lzofXLz3Kuf26AOA== - dependencies: - async-limiter "~1.0.0" - -ws@^6.0.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.1.tgz#442fdf0a47ed64f59b6a5d8ff130f4748ed524fb" - integrity sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA== - dependencies: - async-limiter "~1.0.0" +"ws@^5.2.0 || ^6.0.0 || ^7.0.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.0.tgz#0033bafea031fb9df041b2026fc72a571ca44691" + integrity sha512-6ezXvzOZupqKj4jUqbQ9tXuJNo+BR2gU8fFRk3XCP3e0G6WT414u5ELe6Y0vtp7kmSJ3F7YWObSNr1ESsgi4vw== ws@^7, ws@^7.2.5, ws@^7.4.4: version "7.4.5" @@ -11383,14 +11319,14 @@ xmlchars@^2.2.0: integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== xss@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/xss/-/xss-1.0.8.tgz#32feb87feb74b3dcd3d404b7a68ababf10700535" - integrity sha512-3MgPdaXV8rfQ/pNn16Eio6VXYPTkqwa0vc7GkiymmY/DqR1SE/7VPAAVZz1GJsJFrllMYO3RHfEaiUGjab6TNw== + version "1.0.9" + resolved "https://registry.yarnpkg.com/xss/-/xss-1.0.9.tgz#3ffd565571ff60d2e40db7f3b80b4677bec770d2" + integrity sha512-2t7FahYnGJys6DpHLhajusId7R0Pm2yTmuL0GV9+mV0ZlaLSnb2toBmppATfg5sWIhZQGlsTLoecSzya+l4EAQ== dependencies: commander "^2.20.3" cssfilter "0.0.10" -xtend@^4.0.0, xtend@~4.0.1: +xtend@~4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== @@ -11486,13 +11422,6 @@ yn@3.1.1: resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== -yn@^1.2.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/yn/-/yn-1.3.0.tgz#1b0812abb8d805d48966f8df385dc9dacc9a19d8" - integrity sha1-GwgSq7jYBdSJZvjfOF3J2syaGdg= - dependencies: - object-assign "^4.1.1" - yoga-layout-prebuilt@^1.9.6: version "1.10.0" resolved "https://registry.yarnpkg.com/yoga-layout-prebuilt/-/yoga-layout-prebuilt-1.10.0.tgz#2936fbaf4b3628ee0b3e3b1df44936d6c146faa6" @@ -11513,7 +11442,7 @@ zen-observable@^0.8.0: resolved "https://registry.yarnpkg.com/zen-observable/-/zen-observable-0.8.15.tgz#96415c512d8e3ffd920afd3889604e30b9eaac15" integrity sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ== -zod@3.1.0, zod@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/zod/-/zod-3.1.0.tgz#b9b6c0f949f9b54eb2c32cbbe81e9d0f24a143d8" - integrity sha512-qS0an8oo9EvVLVqIVxMZrQrfR2pVwBtlPp+BzTB/F19IyPTRaLLoFfdXRzgh626pxFR1efuTWV8bPoEE58KwqA== +zod@3.2.0, zod@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/zod/-/zod-3.2.0.tgz#4f06fac3c74e56902eae43a47a1687bf49c9b70b" + integrity sha512-yvcO3FZ8URR+LliMGqaW7tlVOOTzmup3vzKEe9Ds7twyJtdhvYa7dIYr0FbD1wVfWC1OuS83vZfHtCKslPuRhA==