sofa-api 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/{dist/ast.d.ts → ast.d.ts} +7 -7
  2. package/{dist/common.d.ts → common.d.ts} +2 -1
  3. package/express.d.ts +5 -0
  4. package/index.cjs.js +1058 -0
  5. package/{dist/index.d.ts → index.d.ts} +6 -6
  6. package/index.esm.js +1050 -0
  7. package/{dist/logger.d.ts → logger.d.ts} +1 -1
  8. package/{dist/open-api → open-api}/index.d.ts +14 -12
  9. package/{dist/open-api → open-api}/interfaces.d.ts +325 -325
  10. package/{dist/open-api → open-api}/operations.d.ts +7 -7
  11. package/{dist/open-api → open-api}/types.d.ts +3 -3
  12. package/{dist/open-api → open-api}/utils.d.ts +2 -2
  13. package/{dist/operation.d.ts → operation.d.ts} +12 -12
  14. package/package.json +23 -71
  15. package/{dist/parse.d.ts → parse.d.ts} +6 -6
  16. package/{dist/sofa.d.ts → sofa.d.ts} +33 -33
  17. package/{dist/subscriptions.d.ts → subscriptions.d.ts} +38 -38
  18. package/{dist/types.d.ts → types.d.ts} +17 -17
  19. package/.DS_Store +0 -0
  20. package/.git/logs/refs/remotes/origin/changelog +0 -1
  21. package/.git/refs/remotes/origin/changelog +0 -1
  22. package/CHANGELOG.md +0 -30
  23. package/LICENSE +0 -21
  24. package/README.md +0 -276
  25. package/dist/ast.js +0 -16
  26. package/dist/ast.js.map +0 -1
  27. package/dist/common.js +0 -8
  28. package/dist/common.js.map +0 -1
  29. package/dist/express.d.ts +0 -5
  30. package/dist/express.js +0 -226
  31. package/dist/express.js.map +0 -1
  32. package/dist/index.js +0 -13
  33. package/dist/index.js.map +0 -1
  34. package/dist/logger.js +0 -8
  35. package/dist/logger.js.map +0 -1
  36. package/dist/open-api/index.js +0 -67
  37. package/dist/open-api/index.js.map +0 -1
  38. package/dist/open-api/interfaces.js +0 -3
  39. package/dist/open-api/interfaces.js.map +0 -1
  40. package/dist/open-api/operations.js +0 -112
  41. package/dist/open-api/operations.js.map +0 -1
  42. package/dist/open-api/types.js +0 -50
  43. package/dist/open-api/types.js.map +0 -1
  44. package/dist/open-api/utils.js +0 -29
  45. package/dist/open-api/utils.js.map +0 -1
  46. package/dist/operation.js +0 -258
  47. package/dist/operation.js.map +0 -1
  48. package/dist/parse.js +0 -46
  49. package/dist/parse.js.map +0 -1
  50. package/dist/sofa.js +0 -90
  51. package/dist/sofa.js.map +0 -1
  52. package/dist/subscriptions.js +0 -174
  53. package/dist/subscriptions.js.map +0 -1
  54. package/dist/types.js +0 -3
  55. package/dist/types.js.map +0 -1
package/dist/sofa.js DELETED
@@ -1,90 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const graphql_1 = require("graphql");
4
- const common_1 = require("./common");
5
- const logger_1 = require("./logger");
6
- function createSofa(config) {
7
- logger_1.logger.debug('[Sofa] Created');
8
- const models = extractsModels(config.schema);
9
- const ignore = config.ignore || [];
10
- logger_1.logger.debug(`[Sofa] models: ${models.join(', ')}`);
11
- logger_1.logger.debug(`[Sofa] ignore: ${ignore.join(', ')}`);
12
- return Object.assign({ context({ req }) {
13
- return { req };
14
- }, execute: graphql_1.graphql, models,
15
- ignore }, config);
16
- }
17
- exports.createSofa = createSofa;
18
- // Objects and Unions are the only things that are used to define return types
19
- // and both might contain an ID
20
- // We don't treat Unions as models because
21
- // they might represent an Object that is not a model
22
- // We check it later, when an operation is being built
23
- function extractsModels(schema) {
24
- const modelMap = {};
25
- const query = schema.getQueryType();
26
- const fields = query.getFields();
27
- // if Query[type] (no args) and Query[type](just id as an argument)
28
- // loop through every field
29
- for (const fieldName in fields) {
30
- const field = fields[fieldName];
31
- const namedType = graphql_1.getNamedType(field.type);
32
- if (hasID(namedType)) {
33
- if (!modelMap[namedType.name]) {
34
- modelMap[namedType.name] = {};
35
- }
36
- if (isArrayOf(field.type, namedType)) {
37
- // check if type is a list
38
- // check if name of a field matches a name of a named type (in plural)
39
- // check if has no non-optional arguments
40
- // add to registry with `list: true`
41
- const sameName = isNameEqual(field.name, namedType.name + 's');
42
- const allOptionalArguments = !field.args.some(arg => graphql_1.isNonNullType(arg.type));
43
- modelMap[namedType.name].list = sameName && allOptionalArguments;
44
- }
45
- else if (graphql_1.isObjectType(field.type) ||
46
- (graphql_1.isNonNullType(field.type) && graphql_1.isObjectType(field.type.ofType))) {
47
- // check if type is a graphql object type
48
- // check if name of a field matches with name of an object type
49
- // check if has only one argument named `id`
50
- // add to registry with `single: true`
51
- const sameName = isNameEqual(field.name, namedType.name);
52
- const hasIdArgument = field.args.length === 1 && field.args[0].name === 'id';
53
- modelMap[namedType.name].single = sameName && hasIdArgument;
54
- }
55
- }
56
- }
57
- return Object.keys(modelMap).filter(name => modelMap[name].list && modelMap[name].single);
58
- }
59
- // it's dumb but let's leave it for now
60
- function isArrayOf(type, expected) {
61
- if (isOptionalList(type)) {
62
- return true;
63
- }
64
- if (graphql_1.isNonNullType(type) && isOptionalList(type.ofType)) {
65
- return true;
66
- }
67
- function isOptionalList(list) {
68
- if (graphql_1.isListType(list)) {
69
- if (list.ofType.name === expected.name) {
70
- return true;
71
- }
72
- if (graphql_1.isNonNullType(list.ofType) &&
73
- list.ofType.ofType.name === expected.name) {
74
- return true;
75
- }
76
- }
77
- }
78
- return false;
79
- }
80
- function hasID(type) {
81
- return graphql_1.isObjectType(type) && !!type.getFields().id;
82
- }
83
- function isNameEqual(a, b) {
84
- return common_1.convertName(a) === common_1.convertName(b);
85
- }
86
- function isContextFn(context) {
87
- return typeof context === 'function';
88
- }
89
- exports.isContextFn = isContextFn;
90
- //# sourceMappingURL=sofa.js.map
package/dist/sofa.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"sofa.js","sourceRoot":"","sources":["../src/sofa.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n GraphQLSchema,\n graphql,\n isObjectType,\n GraphQLObjectType,\n getNamedType,\n GraphQLNamedType,\n isListType,\n isNonNullType,\n GraphQLOutputType,\n} from 'graphql';\n\nimport {\n Ignore,\n Context,\n ContextFn,\n ExecuteFn,\n OnRoute,\n MethodMap,\n} from './types';\nimport { convertName } from './common';\nimport { logger } from './logger';\nimport { ErrorHandler } from './express';\n\n// user passes:\n// - schema\n// - error handler\n// - execute function\n// - context\n\nexport interface SofaConfig {\n schema: GraphQLSchema;\n context?: Context;\n execute?: ExecuteFn;\n /**\n * Treats an Object with an ID as not a model.\n * @example [\"User\", \"Message.author\"]\n */\n ignore?: Ignore;\n onRoute?: OnRoute;\n depthLimit?: number;\n errorHandler?: ErrorHandler;\n /**\n * Overwrites the default HTTP method.\n * @example {\"Query.field\": \"GET\", \"Mutation.field\": \"POST\"}\n */\n method?: MethodMap;\n}\n\nexport interface Sofa {\n schema: GraphQLSchema;\n context: Context;\n models: string[];\n ignore: Ignore;\n method?: MethodMap;\n execute: ExecuteFn;\n onRoute?: OnRoute;\n errorHandler?: ErrorHandler;\n}\n\nexport function createSofa(config: SofaConfig): Sofa {\n logger.debug('[Sofa] Created');\n\n const models = extractsModels(config.schema);\n const ignore = config.ignore || [];\n\n logger.debug(`[Sofa] models: ${models.join(', ')}`);\n logger.debug(`[Sofa] ignore: ${ignore.join(', ')}`);\n\n return {\n context({ req }) {\n return { req };\n },\n execute: graphql,\n models,\n ignore,\n ...config,\n };\n}\n\n// Objects and Unions are the only things that are used to define return types\n// and both might contain an ID\n// We don't treat Unions as models because\n// they might represent an Object that is not a model\n// We check it later, when an operation is being built\nfunction extractsModels(schema: GraphQLSchema): string[] {\n const modelMap: {\n [name: string]: {\n list?: boolean;\n single?: boolean;\n };\n } = {};\n const query = schema.getQueryType()!;\n const fields = query.getFields();\n\n // if Query[type] (no args) and Query[type](just id as an argument)\n\n // loop through every field\n for (const fieldName in fields) {\n const field = fields[fieldName];\n const namedType = getNamedType(field.type);\n\n if (hasID(namedType)) {\n if (!modelMap[namedType.name]) {\n modelMap[namedType.name] = {};\n }\n\n if (isArrayOf(field.type, namedType)) {\n // check if type is a list\n // check if name of a field matches a name of a named type (in plural)\n // check if has no non-optional arguments\n // add to registry with `list: true`\n const sameName = isNameEqual(field.name, namedType.name + 's');\n const allOptionalArguments = !field.args.some(arg =>\n isNonNullType(arg.type)\n );\n\n modelMap[namedType.name].list = sameName && allOptionalArguments;\n } else if (\n isObjectType(field.type) ||\n (isNonNullType(field.type) && isObjectType(field.type.ofType))\n ) {\n // check if type is a graphql object type\n // check if name of a field matches with name of an object type\n // check if has only one argument named `id`\n // add to registry with `single: true`\n const sameName = isNameEqual(field.name, namedType.name);\n const hasIdArgument =\n field.args.length === 1 && field.args[0].name === 'id';\n\n modelMap[namedType.name].single = sameName && hasIdArgument;\n }\n }\n }\n\n return Object.keys(modelMap).filter(\n name => modelMap[name].list && modelMap[name].single\n );\n}\n\n// it's dumb but let's leave it for now\nfunction isArrayOf(\n type: GraphQLOutputType,\n expected: GraphQLObjectType\n): boolean {\n if (isOptionalList(type)) {\n return true;\n }\n\n if (isNonNullType(type) && isOptionalList(type.ofType)) {\n return true;\n }\n\n function isOptionalList(list: GraphQLOutputType) {\n if (isListType(list)) {\n if (list.ofType.name === expected.name) {\n return true;\n }\n\n if (\n isNonNullType(list.ofType) &&\n list.ofType.ofType.name === expected.name\n ) {\n return true;\n }\n }\n }\n\n return false;\n}\n\nfunction hasID(type: GraphQLNamedType): type is GraphQLObjectType {\n return isObjectType(type) && !!type.getFields().id;\n}\n\nfunction isNameEqual(a: string, b: string): boolean {\n return convertName(a) === convertName(b);\n}\n\nexport function isContextFn(context: any): context is ContextFn {\n return typeof context === 'function';\n}\n"]}
@@ -1,174 +0,0 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- Object.defineProperty(exports, "__esModule", { value: true });
12
- const graphql_1 = require("graphql");
13
- const uuid = require("uuid/v4");
14
- const request = require("request-promise-native");
15
- const iterall_1 = require("iterall");
16
- const operation_1 = require("./operation");
17
- const sofa_1 = require("./sofa");
18
- const ast_1 = require("./ast");
19
- const parse_1 = require("./parse");
20
- const logger_1 = require("./logger");
21
- class SubscriptionManager {
22
- constructor(sofa) {
23
- this.sofa = sofa;
24
- this.operations = new Map();
25
- this.clients = new Map();
26
- this.buildOperations();
27
- }
28
- start(event, { req, res, }) {
29
- return __awaiter(this, void 0, void 0, function* () {
30
- const id = uuid();
31
- const name = event.subscription;
32
- if (!this.operations.has(name)) {
33
- throw new Error(`Subscription '${name}' is not available`);
34
- }
35
- const { document, operationName, variables } = this.operations.get(name);
36
- logger_1.logger.info(`[Subscription] Start ${id}`, event);
37
- const result = yield this.execute({
38
- id,
39
- name,
40
- url: event.url,
41
- document,
42
- operationName,
43
- variables,
44
- req,
45
- res,
46
- });
47
- if (typeof result !== 'undefined') {
48
- return result;
49
- }
50
- return { id };
51
- });
52
- }
53
- stop(id) {
54
- return __awaiter(this, void 0, void 0, function* () {
55
- logger_1.logger.info(`[Subscription] Stop ${id}`);
56
- if (!this.clients.has(id)) {
57
- throw new Error(`Subscription with ID '${id}' does not exist`);
58
- }
59
- const execution = this.clients.get(id);
60
- if (execution.iterator.return) {
61
- execution.iterator.return();
62
- }
63
- this.clients.delete(id);
64
- return { id };
65
- });
66
- }
67
- update(event, { req, res, }) {
68
- return __awaiter(this, void 0, void 0, function* () {
69
- const { variables, id } = event;
70
- logger_1.logger.info(`[Subscription] Update ${id}`, event);
71
- if (!this.clients.has(id)) {
72
- throw new Error(`Subscription with ID '${id}' does not exist`);
73
- }
74
- const { name: subscription, url } = this.clients.get(id);
75
- this.stop(id);
76
- return this.start({
77
- url,
78
- subscription,
79
- variables,
80
- }, {
81
- req,
82
- res,
83
- });
84
- });
85
- }
86
- execute({ id, document, name, url, operationName, variables, req, res, }) {
87
- return __awaiter(this, void 0, void 0, function* () {
88
- const variableNodes = this.operations.get(name).variables;
89
- const variableValues = variableNodes.reduce((values, variable) => {
90
- const value = parse_1.parseVariable({
91
- value: variables[variable.variable.name.value],
92
- variable,
93
- schema: this.sofa.schema,
94
- });
95
- if (typeof value === 'undefined') {
96
- return values;
97
- }
98
- return Object.assign(Object.assign({}, values), { [name]: value });
99
- }, {});
100
- const C = sofa_1.isContextFn(this.sofa.context)
101
- ? yield this.sofa.context({ req, res })
102
- : this.sofa.context;
103
- const execution = yield graphql_1.subscribe({
104
- schema: this.sofa.schema,
105
- document,
106
- operationName,
107
- variableValues,
108
- contextValue: C,
109
- });
110
- if (iterall_1.isAsyncIterable(execution)) {
111
- // successful
112
- // add execution to clients
113
- this.clients.set(id, {
114
- name,
115
- url,
116
- iterator: execution,
117
- });
118
- // success
119
- iterall_1.forAwaitEach(execution, (result) => __awaiter(this, void 0, void 0, function* () {
120
- yield this.sendData({
121
- id,
122
- result,
123
- });
124
- })).then(() => {
125
- // completes
126
- this.stop(id);
127
- }, e => {
128
- logger_1.logger.info(`Subscription #${id} closed`);
129
- console.log(e);
130
- this.stop(id);
131
- });
132
- }
133
- else {
134
- return execution;
135
- }
136
- });
137
- }
138
- sendData({ id, result }) {
139
- return __awaiter(this, void 0, void 0, function* () {
140
- if (!this.clients.has(id)) {
141
- throw new Error(`Subscription with ID '${id}' does not exist`);
142
- }
143
- const { url } = this.clients.get(id);
144
- logger_1.logger.info(`[Subscription] Trigger ${id}`);
145
- yield request.post(url, {
146
- json: result,
147
- });
148
- });
149
- }
150
- buildOperations() {
151
- const subscription = this.sofa.schema.getSubscriptionType();
152
- if (!subscription) {
153
- return;
154
- }
155
- const fieldMap = subscription.getFields();
156
- for (const field in fieldMap) {
157
- const document = operation_1.buildOperation({
158
- kind: 'subscription',
159
- field,
160
- schema: this.sofa.schema,
161
- models: this.sofa.models,
162
- ignore: this.sofa.ignore,
163
- });
164
- const { variables, name: operationName } = ast_1.getOperationInfo(document);
165
- this.operations.set(field, {
166
- operationName,
167
- document,
168
- variables,
169
- });
170
- }
171
- }
172
- }
173
- exports.SubscriptionManager = SubscriptionManager;
174
- //# sourceMappingURL=subscriptions.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"subscriptions.js","sourceRoot":"","sources":["../src/subscriptions.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n subscribe,\n DocumentNode,\n VariableDefinitionNode,\n ExecutionResult,\n} from 'graphql';\nimport * as uuid from 'uuid/v4';\nimport * as request from 'request-promise-native';\nimport { forAwaitEach, isAsyncIterable } from 'iterall';\nimport { buildOperation } from './operation';\nimport { Sofa, isContextFn } from './sofa';\nimport { getOperationInfo } from './ast';\nimport { parseVariable } from './parse';\nimport { logger } from './logger';\n\n// To start subscription:\n// - an url that Sofa should trigger\n// - name of a subscription\n// - variables if needed\n// - some sort of an auth token\n// - Sofa should return a unique id of that subscription\n// - respond with OK 200\n\n// To stop subscription\n// - an id is required\n// - respond with OK 200\n\n// To update subscription\n// - an id is required\n// - new set of variables\n\nexport type ID = string;\nexport type SubscriptionFieldName = string;\n\nexport interface StartSubscriptionEvent {\n subscription: SubscriptionFieldName;\n variables: any;\n url: string;\n}\n\nexport interface UpdateSubscriptionEvent {\n id: ID;\n variables: any;\n}\n\nexport interface StopSubscriptionResponse {\n id: ID;\n}\n\ninterface BuiltOperation {\n operationName: string;\n document: DocumentNode;\n variables: ReadonlyArray<VariableDefinitionNode>;\n}\n\ninterface StoredClient {\n name: SubscriptionFieldName;\n url: string;\n iterator: AsyncIterator<any>;\n}\n\nexport class SubscriptionManager {\n private operations = new Map<SubscriptionFieldName, BuiltOperation>();\n private clients = new Map<ID, StoredClient>();\n\n constructor(private sofa: Sofa) {\n this.buildOperations();\n }\n\n public async start(\n event: StartSubscriptionEvent,\n {\n req,\n res,\n }: {\n req: any;\n res: any;\n }\n ) {\n const id = uuid();\n const name = event.subscription;\n\n if (!this.operations.has(name)) {\n throw new Error(`Subscription '${name}' is not available`);\n }\n\n const { document, operationName, variables } = this.operations.get(name)!;\n\n logger.info(`[Subscription] Start ${id}`, event);\n\n const result = await this.execute({\n id,\n name,\n url: event.url,\n document,\n operationName,\n variables,\n req,\n res,\n });\n\n if (typeof result !== 'undefined') {\n return result;\n }\n\n return { id };\n }\n\n public async stop(id: ID): Promise<StopSubscriptionResponse> {\n logger.info(`[Subscription] Stop ${id}`);\n\n if (!this.clients.has(id)) {\n throw new Error(`Subscription with ID '${id}' does not exist`);\n }\n\n const execution = this.clients.get(id)!;\n\n if (execution.iterator.return) {\n execution.iterator.return();\n }\n\n this.clients.delete(id);\n\n return { id };\n }\n\n public async update(\n event: UpdateSubscriptionEvent,\n {\n req,\n res,\n }: {\n req: any;\n res: any;\n }\n ) {\n const { variables, id } = event;\n\n logger.info(`[Subscription] Update ${id}`, event);\n\n if (!this.clients.has(id)) {\n throw new Error(`Subscription with ID '${id}' does not exist`);\n }\n\n const { name: subscription, url } = this.clients.get(id)!;\n\n this.stop(id);\n\n return this.start(\n {\n url,\n subscription,\n variables,\n },\n {\n req,\n res,\n }\n );\n }\n\n private async execute({\n id,\n document,\n name,\n url,\n operationName,\n variables,\n req,\n res,\n }: {\n id: ID;\n name: SubscriptionFieldName;\n url: string;\n document: DocumentNode;\n operationName: string;\n variables: Record<string, any>;\n req: any;\n res: any;\n }) {\n const variableNodes = this.operations.get(name)!.variables;\n const variableValues = variableNodes.reduce((values, variable) => {\n const value = parseVariable({\n value: variables[variable.variable.name.value],\n variable,\n schema: this.sofa.schema,\n });\n\n if (typeof value === 'undefined') {\n return values;\n }\n\n return {\n ...values,\n [name]: value,\n };\n }, {});\n\n const C = isContextFn(this.sofa.context)\n ? await this.sofa.context({ req, res })\n : this.sofa.context;\n const execution = await subscribe({\n schema: this.sofa.schema,\n document,\n operationName,\n variableValues,\n contextValue: C,\n });\n\n if (isAsyncIterable(execution)) {\n // successful\n\n // add execution to clients\n this.clients.set(id, {\n name,\n url,\n iterator: execution as any,\n });\n\n // success\n forAwaitEach(execution, async result => {\n await this.sendData({\n id,\n result,\n });\n }).then(\n () => {\n // completes\n this.stop(id);\n },\n e => {\n logger.info(`Subscription #${id} closed`);\n console.log(e);\n this.stop(id);\n }\n );\n } else {\n return execution as ExecutionResult<any>;\n }\n }\n\n private async sendData({ id, result }: { id: ID; result: any }) {\n if (!this.clients.has(id)) {\n throw new Error(`Subscription with ID '${id}' does not exist`);\n }\n\n const { url } = this.clients.get(id)!;\n\n logger.info(`[Subscription] Trigger ${id}`);\n\n await request.post(url, {\n json: result,\n });\n }\n\n private buildOperations() {\n const subscription = this.sofa.schema.getSubscriptionType();\n\n if (!subscription) {\n return;\n }\n\n const fieldMap = subscription.getFields();\n\n for (const field in fieldMap) {\n const document = buildOperation({\n kind: 'subscription',\n field,\n schema: this.sofa.schema,\n models: this.sofa.models,\n ignore: this.sofa.ignore,\n });\n\n const { variables, name: operationName } = getOperationInfo(document)!;\n\n this.operations.set(field, {\n operationName,\n document,\n variables,\n });\n }\n }\n}\n"]}
package/dist/types.js DELETED
@@ -1,3 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- //# sourceMappingURL=types.js.map
package/dist/types.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["import { GraphQLArgs, ExecutionResult, DocumentNode } from 'graphql';\n\nexport type ContextValue = Record<string, any>;\nexport type ContextFn = (init: { req: any; res: any }) => ContextValue;\nexport type Context = ContextValue | ContextFn;\n\nexport type Ignore = string[];\n\nexport type ExecuteFn = (args: GraphQLArgs) => Promise<ExecutionResult<any>>;\n\nexport type Method = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';\n\nexport interface RouteInfo {\n document: DocumentNode;\n path: string;\n method: Method;\n}\nexport type OnRoute = (info: RouteInfo) => void;\n\nexport type MethodMap = Record<string, Method>;\n"]}