Initial Save

This commit is contained in:
jackbeeby
2025-03-28 12:30:19 +11:00
parent e381994f19
commit d8773925e8
9910 changed files with 982718 additions and 0 deletions

10
node_modules/graphql-extensions/CHANGELOG.md generated vendored Normal file
View File

@@ -0,0 +1,10 @@
# Changelog
> This package is deprecated. Please use the [Apollo Server Plugin API](https://www.apollographql.com/docs/apollo-server/integrations/plugins/) (specified on the `plugins` property, rather than `extensions`), which provides the same functionality (and more).
### 0.1.0-beta
- *Backwards-incompatible change*: `fooDidStart` handlers (where foo is `request`, `parsing`, `validation`, and `execution`) now return their end handler; the `fooDidEnd` handlers no longer exist. The end handlers now take errors. There is a new `willSendResponse` handler. The `fooDidStart` handlers take extra options (eg, the `ExecutionArgs` for `executionDidStart`).
- *Backwards-incompatible change*: Previously, the `GraphQLExtensionStack` constructor took either `GraphQLExtension` objects or their constructors. Now you may only pass in `GraphQLExtension` objects.
### 0.0.10
- Fix lifecycle method invocations on extensions

21
node_modules/graphql-extensions/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2016-2020 Apollo Graph, Inc. (Formerly Meteor Development Group, Inc.)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

4
node_modules/graphql-extensions/README.md generated vendored Normal file
View File

@@ -0,0 +1,4 @@
# graphql-extensions
[![npm version](https://badge.fury.io/js/graphql-extensions.svg)](https://badge.fury.io/js/graphql-extensions)
[![Build Status](https://circleci.com/gh/apollographql/apollo-server/tree/main.svg?style=svg)](https://circleci.com/gh/apollographql/apollo-server)

85
node_modules/graphql-extensions/dist/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,85 @@
import { GraphQLSchema, GraphQLField, GraphQLFieldResolver, GraphQLResolveInfo, ExecutionArgs, DocumentNode, GraphQLError } from 'graphql';
import { Request } from 'apollo-server-env';
import { GraphQLResponse, GraphQLRequestContext } from 'apollo-server-types';
export { GraphQLResponse };
export declare type EndHandler = (...errors: Array<Error>) => void;
export declare class GraphQLExtension<TContext = any> {
requestDidStart?(o: {
request: Pick<Request, 'url' | 'method' | 'headers'>;
queryString?: string;
parsedQuery?: DocumentNode;
operationName?: string;
variables?: {
[key: string]: any;
};
persistedQueryHit?: boolean;
persistedQueryRegister?: boolean;
context: TContext;
requestContext: GraphQLRequestContext<TContext>;
}): EndHandler | void;
parsingDidStart?(o: {
queryString: string;
}): EndHandler | void;
validationDidStart?(): EndHandler | void;
executionDidStart?(o: {
executionArgs: ExecutionArgs;
}): EndHandler | void;
didEncounterErrors?(errors: ReadonlyArray<GraphQLError>): void;
willSendResponse?(o: {
graphqlResponse: GraphQLResponse;
context: TContext;
}): void | {
graphqlResponse: GraphQLResponse;
context: TContext;
};
willResolveField?(source: any, args: {
[argName: string]: any;
}, context: TContext, info: GraphQLResolveInfo): ((error: Error | null, result?: any) => void) | void;
format?(): [string, any] | undefined;
}
export declare class GraphQLExtensionStack<TContext = any> {
fieldResolver?: GraphQLFieldResolver<any, any>;
private extensions;
constructor(extensions: GraphQLExtension<TContext>[]);
requestDidStart(o: {
request: Pick<Request, 'url' | 'method' | 'headers'>;
queryString?: string;
parsedQuery?: DocumentNode;
operationName?: string;
variables?: {
[key: string]: any;
};
persistedQueryHit?: boolean;
persistedQueryRegister?: boolean;
context: TContext;
extensions?: Record<string, any>;
requestContext: GraphQLRequestContext<TContext>;
}): EndHandler;
parsingDidStart(o: {
queryString: string;
}): EndHandler;
validationDidStart(): EndHandler;
executionDidStart(o: {
executionArgs: ExecutionArgs;
}): EndHandler;
didEncounterErrors(errors: ReadonlyArray<GraphQLError>): void;
willSendResponse(o: {
graphqlResponse: GraphQLResponse;
context: TContext;
}): {
graphqlResponse: GraphQLResponse;
context: TContext;
};
willResolveField(source: any, args: {
[argName: string]: any;
}, context: TContext, info: GraphQLResolveInfo): (error: Error | null, result?: any) => void;
format(): {};
private handleDidStart;
}
export declare function enableGraphQLExtensions(schema: GraphQLSchema & {
_extensionsEnabled?: boolean;
}): GraphQLSchema & {
_extensionsEnabled?: boolean | undefined;
};
export declare type FieldIteratorFn = (fieldDef: GraphQLField<any, any>, typeName: string, fieldName: string) => void;
//# sourceMappingURL=index.d.ts.map

1
node_modules/graphql-extensions/dist/index.d.ts.map generated vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}

178
node_modules/graphql-extensions/dist/index.js generated vendored Normal file
View File

@@ -0,0 +1,178 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.enableGraphQLExtensions = exports.GraphQLExtensionStack = exports.GraphQLExtension = void 0;
const graphql_1 = require("graphql");
class GraphQLExtension {
}
exports.GraphQLExtension = GraphQLExtension;
class GraphQLExtensionStack {
constructor(extensions) {
this.extensions = extensions;
}
requestDidStart(o) {
return this.handleDidStart(ext => ext.requestDidStart && ext.requestDidStart(o));
}
parsingDidStart(o) {
return this.handleDidStart(ext => ext.parsingDidStart && ext.parsingDidStart(o));
}
validationDidStart() {
return this.handleDidStart(ext => ext.validationDidStart && ext.validationDidStart());
}
executionDidStart(o) {
if (o.executionArgs.fieldResolver) {
this.fieldResolver = o.executionArgs.fieldResolver;
}
return this.handleDidStart(ext => ext.executionDidStart && ext.executionDidStart(o));
}
didEncounterErrors(errors) {
this.extensions.forEach(extension => {
if (extension.didEncounterErrors) {
extension.didEncounterErrors(errors);
}
});
}
willSendResponse(o) {
let reference = o;
[...this.extensions].reverse().forEach(extension => {
if (extension.willSendResponse) {
const result = extension.willSendResponse(reference);
if (result) {
reference = result;
}
}
});
return reference;
}
willResolveField(source, args, context, info) {
const handlers = this.extensions
.map(extension => extension.willResolveField &&
extension.willResolveField(source, args, context, info))
.filter(x => x)
.reverse();
return (error, result) => {
for (const handler of handlers) {
handler(error, result);
}
};
}
format() {
return this.extensions
.map(extension => extension.format && extension.format())
.filter(x => x).reduce((extensions, [key, value]) => Object.assign(extensions, { [key]: value }), {});
}
handleDidStart(startInvoker) {
const endHandlers = [];
this.extensions.forEach(extension => {
try {
const endHandler = startInvoker(extension);
if (endHandler) {
endHandlers.push(endHandler);
}
}
catch (error) {
console.error(error);
}
});
return (...errors) => {
endHandlers.reverse();
for (const endHandler of endHandlers) {
try {
endHandler(...errors);
}
catch (error) {
console.error(error);
}
}
};
}
}
exports.GraphQLExtensionStack = GraphQLExtensionStack;
function enableGraphQLExtensions(schema) {
if (schema._extensionsEnabled) {
return schema;
}
schema._extensionsEnabled = true;
forEachField(schema, wrapField);
return schema;
}
exports.enableGraphQLExtensions = enableGraphQLExtensions;
function wrapField(field) {
const fieldResolver = field.resolve;
field.resolve = (source, args, context, info) => {
const parentPath = info.path.prev;
const extensionStack = context && context._extensionStack;
const handler = (extensionStack &&
extensionStack.willResolveField(source, args, context, info)) ||
((_err, _result) => {
});
const resolveObject = info.parentType.resolveObject;
let whenObjectResolved;
if (parentPath && resolveObject) {
if (!parentPath.__fields) {
parentPath.__fields = {};
}
parentPath.__fields[info.fieldName] = info.fieldNodes;
whenObjectResolved = parentPath.__whenObjectResolved;
if (!whenObjectResolved) {
whenObjectResolved = Promise.resolve().then(() => {
return resolveObject(source, parentPath.__fields, context, info);
});
parentPath.__whenObjectResolved = whenObjectResolved;
}
}
try {
const actualFieldResolver = fieldResolver ||
(extensionStack && extensionStack.fieldResolver) ||
graphql_1.defaultFieldResolver;
let result;
if (whenObjectResolved) {
result = whenObjectResolved.then((resolvedObject) => {
return actualFieldResolver(resolvedObject, args, context, info);
});
}
else {
result = actualFieldResolver(source, args, context, info);
}
whenResultIsFinished(result, handler);
return result;
}
catch (error) {
handler(error);
throw error;
}
};
}
function isPromise(x) {
return x && typeof x.then === 'function';
}
function whenResultIsFinished(result, callback) {
if (isPromise(result)) {
result.then((r) => callback(null, r), (err) => callback(err));
}
else if (Array.isArray(result)) {
if (result.some(isPromise)) {
Promise.all(result).then((r) => callback(null, r), (err) => callback(err));
}
else {
callback(null, result);
}
}
else {
callback(null, result);
}
}
function forEachField(schema, fn) {
const typeMap = schema.getTypeMap();
Object.keys(typeMap).forEach(typeName => {
const type = typeMap[typeName];
if (!graphql_1.getNamedType(type).name.startsWith('__') &&
type instanceof graphql_1.GraphQLObjectType) {
const fields = type.getFields();
Object.keys(fields).forEach(fieldName => {
const field = fields[fieldName];
fn(field, typeName, fieldName);
});
}
});
}
//# sourceMappingURL=index.js.map

1
node_modules/graphql-extensions/dist/index.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long

26
node_modules/graphql-extensions/package.json generated vendored Normal file
View File

@@ -0,0 +1,26 @@
{
"name": "graphql-extensions",
"version": "0.16.0",
"description": "Add extensions to GraphQL servers",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"repository": {
"type": "git",
"url": "apollographql/apollo-server",
"directory": "packages/graphql-extensions"
},
"author": "Apollo <opensource@apollographql.com>",
"license": "MIT",
"engines": {
"node": ">=6.0"
},
"dependencies": {
"@apollographql/apollo-tools": "^0.5.0",
"apollo-server-env": "^3.2.0",
"apollo-server-types": "^0.10.0"
},
"peerDependencies": {
"graphql": "^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0"
},
"gitHead": "91de501bb389c07ccfc5e684811153267b91e9ac"
}

341
node_modules/graphql-extensions/src/index.ts generated vendored Normal file
View File

@@ -0,0 +1,341 @@
import {
GraphQLSchema,
GraphQLObjectType,
getNamedType,
GraphQLField,
defaultFieldResolver,
GraphQLFieldResolver,
GraphQLResolveInfo,
ExecutionArgs,
DocumentNode,
ResponsePath,
FieldNode,
GraphQLError,
} from 'graphql';
import { Request } from 'apollo-server-env';
import { GraphQLResponse, GraphQLRequestContext } from 'apollo-server-types';
export { GraphQLResponse };
import { GraphQLObjectResolver } from '@apollographql/apollo-tools';
export type EndHandler = (...errors: Array<Error>) => void;
// A StartHandlerInvoker is a function that, given a specific GraphQLExtension,
// finds a specific StartHandler on that extension and calls it with appropriate
// arguments.
type StartHandlerInvoker<TContext = any> = (
ext: GraphQLExtension<TContext>,
) => EndHandler | void;
export class GraphQLExtension<TContext = any> {
public requestDidStart?(o: {
request: Pick<Request, 'url' | 'method' | 'headers'>;
queryString?: string;
parsedQuery?: DocumentNode;
operationName?: string;
variables?: { [key: string]: any };
persistedQueryHit?: boolean;
persistedQueryRegister?: boolean;
context: TContext;
requestContext: GraphQLRequestContext<TContext>;
}): EndHandler | void;
public parsingDidStart?(o: { queryString: string }): EndHandler | void;
public validationDidStart?(): EndHandler | void;
public executionDidStart?(o: {
executionArgs: ExecutionArgs;
}): EndHandler | void;
public didEncounterErrors?(errors: ReadonlyArray<GraphQLError>): void;
public willSendResponse?(o: {
graphqlResponse: GraphQLResponse;
context: TContext;
}): void | { graphqlResponse: GraphQLResponse; context: TContext };
public willResolveField?(
source: any,
args: { [argName: string]: any },
context: TContext,
info: GraphQLResolveInfo,
): ((error: Error | null, result?: any) => void) | void;
public format?(): [string, any] | undefined;
}
export class GraphQLExtensionStack<TContext = any> {
public fieldResolver?: GraphQLFieldResolver<any, any>;
private extensions: GraphQLExtension<TContext>[];
constructor(extensions: GraphQLExtension<TContext>[]) {
this.extensions = extensions;
}
public requestDidStart(o: {
request: Pick<Request, 'url' | 'method' | 'headers'>;
queryString?: string;
parsedQuery?: DocumentNode;
operationName?: string;
variables?: { [key: string]: any };
persistedQueryHit?: boolean;
persistedQueryRegister?: boolean;
context: TContext;
extensions?: Record<string, any>;
requestContext: GraphQLRequestContext<TContext>;
}): EndHandler {
return this.handleDidStart(
ext => ext.requestDidStart && ext.requestDidStart(o),
);
}
public parsingDidStart(o: { queryString: string }): EndHandler {
return this.handleDidStart(
ext => ext.parsingDidStart && ext.parsingDidStart(o),
);
}
public validationDidStart(): EndHandler {
return this.handleDidStart(
ext => ext.validationDidStart && ext.validationDidStart(),
);
}
public executionDidStart(o: { executionArgs: ExecutionArgs }): EndHandler {
if (o.executionArgs.fieldResolver) {
this.fieldResolver = o.executionArgs.fieldResolver;
}
return this.handleDidStart(
ext => ext.executionDidStart && ext.executionDidStart(o),
);
}
public didEncounterErrors(errors: ReadonlyArray<GraphQLError>) {
this.extensions.forEach(extension => {
if (extension.didEncounterErrors) {
extension.didEncounterErrors(errors);
}
});
}
public willSendResponse(o: {
graphqlResponse: GraphQLResponse;
context: TContext;
}): { graphqlResponse: GraphQLResponse; context: TContext } {
let reference = o;
// Reverse the array, since this is functions as an end handler
[...this.extensions].reverse().forEach(extension => {
if (extension.willSendResponse) {
const result = extension.willSendResponse(reference);
if (result) {
reference = result;
}
}
});
return reference;
}
public willResolveField(
source: any,
args: { [argName: string]: any },
context: TContext,
info: GraphQLResolveInfo,
) {
const handlers = this.extensions
.map(
extension =>
extension.willResolveField &&
extension.willResolveField(source, args, context, info),
)
.filter(x => x)
// Reverse list so that handlers "nest", like in handleDidStart.
.reverse() as ((error: Error | null, result?: any) => void)[];
return (error: Error | null, result?: any) => {
for (const handler of handlers) {
handler(error, result);
}
};
}
public format() {
return (this.extensions
.map(extension => extension.format && extension.format())
.filter(x => x) as [string, any][]).reduce(
(extensions, [key, value]) => Object.assign(extensions, { [key]: value }),
{},
);
}
private handleDidStart(startInvoker: StartHandlerInvoker): EndHandler {
const endHandlers: EndHandler[] = [];
this.extensions.forEach(extension => {
// Invoke the start handler, which may return an end handler.
try {
const endHandler = startInvoker(extension);
if (endHandler) {
endHandlers.push(endHandler);
}
} catch (error) {
console.error(error);
}
});
return (...errors: Array<Error>) => {
// We run end handlers in reverse order of start handlers. That way, the
// first handler in the stack "surrounds" the entire event's process
// (helpful for tracing/reporting!)
endHandlers.reverse();
for (const endHandler of endHandlers) {
try {
endHandler(...errors);
} catch (error) {
console.error(error);
}
}
};
}
}
export function enableGraphQLExtensions(
schema: GraphQLSchema & { _extensionsEnabled?: boolean },
) {
if (schema._extensionsEnabled) {
return schema;
}
schema._extensionsEnabled = true;
forEachField(schema, wrapField);
return schema;
}
function wrapField(field: GraphQLField<any, any>): void {
const fieldResolver = field.resolve;
field.resolve = (source, args, context, info) => {
// This is a bit of a hack, but since `ResponsePath` is a linked list,
// a new object gets created every time a path segment is added.
// So we can use that to share our `whenObjectResolved` promise across
// all field resolvers for the same object.
const parentPath = info.path.prev as ResponsePath & {
__fields?: Record<string, ReadonlyArray<FieldNode>>;
__whenObjectResolved?: Promise<any>;
};
const extensionStack = context && context._extensionStack;
const handler =
(extensionStack &&
extensionStack.willResolveField(source, args, context, info)) ||
((_err: Error | null, _result?: any) => {
/* do nothing */
});
const resolveObject: GraphQLObjectResolver<
any,
any
> = (info.parentType as any).resolveObject;
let whenObjectResolved: Promise<any> | undefined;
if (parentPath && resolveObject) {
if (!parentPath.__fields) {
parentPath.__fields = {};
}
parentPath.__fields[info.fieldName] = info.fieldNodes;
whenObjectResolved = parentPath.__whenObjectResolved;
if (!whenObjectResolved) {
// Use `Promise.resolve().then()` to delay executing
// `resolveObject()` so we can collect all the fields first.
whenObjectResolved = Promise.resolve().then(() => {
return resolveObject(source, parentPath.__fields!, context, info);
});
parentPath.__whenObjectResolved = whenObjectResolved;
}
}
try {
// If no resolver has been defined for a field, use either the configured
// field resolver or the default field resolver
// (which matches the behavior of graphql-js when there is no explicit
// resolve function defined).
// XXX: Can't this be pulled up to the top of `wrapField` and only
// assigned once? It seems `extensionStack.fieldResolver` isn't set
// anywhere?
const actualFieldResolver =
fieldResolver ||
(extensionStack && extensionStack.fieldResolver) ||
defaultFieldResolver;
let result: any;
if (whenObjectResolved) {
result = whenObjectResolved.then((resolvedObject: any) => {
return actualFieldResolver(resolvedObject, args, context, info);
});
} else {
result = actualFieldResolver(source, args, context, info);
}
// Call the stack's handlers either immediately (if result is not a
// Promise) or once the Promise is done. Then return that same
// maybe-Promise value.
whenResultIsFinished(result, handler);
return result;
} catch (error) {
// Normally it's a bad sign to see an error both handled and
// re-thrown. But it is useful to allow extensions to track errors while
// still handling them in the normal GraphQL way.
handler(error);
throw error;
}
};
}
function isPromise(x: any): boolean {
return x && typeof x.then === 'function';
}
// Given result (which may be a Promise or an array some of whose elements are
// promises) Promises, set up 'callback' to be invoked when result is fully
// resolved.
function whenResultIsFinished(
result: any,
callback: (err: Error | null, result?: any) => void,
) {
if (isPromise(result)) {
result.then((r: any) => callback(null, r), (err: Error) => callback(err));
} else if (Array.isArray(result)) {
if (result.some(isPromise)) {
Promise.all(result).then(
(r: any) => callback(null, r),
(err: Error) => callback(err),
);
} else {
callback(null, result);
}
} else {
callback(null, result);
}
}
function forEachField(schema: GraphQLSchema, fn: FieldIteratorFn): void {
const typeMap = schema.getTypeMap();
Object.keys(typeMap).forEach(typeName => {
const type = typeMap[typeName];
if (
!getNamedType(type).name.startsWith('__') &&
type instanceof GraphQLObjectType
) {
const fields = type.getFields();
Object.keys(fields).forEach(fieldName => {
const field = fields[fieldName];
fn(field, typeName, fieldName);
});
}
});
}
export type FieldIteratorFn = (
fieldDef: GraphQLField<any, any>,
typeName: string,
fieldName: string,
) => void;