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.
- package/{dist/ast.d.ts → ast.d.ts} +7 -7
- package/{dist/common.d.ts → common.d.ts} +2 -1
- package/express.d.ts +5 -0
- package/index.cjs.js +1058 -0
- package/{dist/index.d.ts → index.d.ts} +6 -6
- package/index.esm.js +1050 -0
- package/{dist/logger.d.ts → logger.d.ts} +1 -1
- package/{dist/open-api → open-api}/index.d.ts +14 -12
- package/{dist/open-api → open-api}/interfaces.d.ts +325 -325
- package/{dist/open-api → open-api}/operations.d.ts +7 -7
- package/{dist/open-api → open-api}/types.d.ts +3 -3
- package/{dist/open-api → open-api}/utils.d.ts +2 -2
- package/{dist/operation.d.ts → operation.d.ts} +12 -12
- package/package.json +23 -71
- package/{dist/parse.d.ts → parse.d.ts} +6 -6
- package/{dist/sofa.d.ts → sofa.d.ts} +33 -33
- package/{dist/subscriptions.d.ts → subscriptions.d.ts} +38 -38
- package/{dist/types.d.ts → types.d.ts} +17 -17
- package/.DS_Store +0 -0
- package/.git/logs/refs/remotes/origin/changelog +0 -1
- package/.git/refs/remotes/origin/changelog +0 -1
- package/CHANGELOG.md +0 -30
- package/LICENSE +0 -21
- package/README.md +0 -276
- package/dist/ast.js +0 -16
- package/dist/ast.js.map +0 -1
- package/dist/common.js +0 -8
- package/dist/common.js.map +0 -1
- package/dist/express.d.ts +0 -5
- package/dist/express.js +0 -226
- package/dist/express.js.map +0 -1
- package/dist/index.js +0 -13
- package/dist/index.js.map +0 -1
- package/dist/logger.js +0 -8
- package/dist/logger.js.map +0 -1
- package/dist/open-api/index.js +0 -67
- package/dist/open-api/index.js.map +0 -1
- package/dist/open-api/interfaces.js +0 -3
- package/dist/open-api/interfaces.js.map +0 -1
- package/dist/open-api/operations.js +0 -112
- package/dist/open-api/operations.js.map +0 -1
- package/dist/open-api/types.js +0 -50
- package/dist/open-api/types.js.map +0 -1
- package/dist/open-api/utils.js +0 -29
- package/dist/open-api/utils.js.map +0 -1
- package/dist/operation.js +0 -258
- package/dist/operation.js.map +0 -1
- package/dist/parse.js +0 -46
- package/dist/parse.js.map +0 -1
- package/dist/sofa.js +0 -90
- package/dist/sofa.js.map +0 -1
- package/dist/subscriptions.js +0 -174
- package/dist/subscriptions.js.map +0 -1
- package/dist/types.js +0 -3
- 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"]}
|
package/dist/subscriptions.js
DELETED
|
@@ -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
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"]}
|