@envelop/core 2.5.1-alpha-20220824165935-4720f031 → 2.6.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/cjs/create.js +5 -7
- package/cjs/index.js +3 -3
- package/cjs/orchestrator.js +16 -24
- package/cjs/plugins/use-immediate-introspection.js +50 -0
- package/cjs/plugins/use-masked-errors.js +93 -0
- package/cjs/plugins/use-timing.js +138 -0
- package/cjs/traced-orchestrator.js +136 -0
- package/cjs/traced-schema.js +68 -0
- package/cjs/utils.js +26 -1
- package/esm/create.js +5 -7
- package/esm/index.js +3 -1
- package/esm/orchestrator.js +5 -13
- package/esm/plugins/use-immediate-introspection.js +46 -0
- package/esm/plugins/use-masked-errors.js +87 -0
- package/esm/plugins/use-timing.js +134 -0
- package/esm/traced-orchestrator.js +132 -0
- package/esm/traced-schema.js +64 -0
- package/esm/utils.js +22 -0
- package/package.json +6 -2
- package/typings/create.d.cts +1 -5
- package/typings/create.d.ts +1 -5
- package/typings/enable-if.d.cts +1 -1
- package/typings/enable-if.d.ts +1 -1
- package/typings/index.d.cts +3 -1
- package/typings/index.d.ts +3 -1
- package/typings/orchestrator.d.cts +4 -12
- package/typings/orchestrator.d.ts +4 -12
- package/typings/plugins/use-error-handler.d.cts +3 -2
- package/typings/plugins/use-error-handler.d.ts +3 -2
- package/typings/plugins/use-immediate-introspection.d.cts +6 -0
- package/typings/plugins/use-immediate-introspection.d.ts +6 -0
- package/typings/plugins/use-masked-errors.d.cts +39 -0
- package/typings/plugins/use-masked-errors.d.ts +39 -0
- package/typings/plugins/use-payload-formatter.d.cts +2 -1
- package/typings/plugins/use-payload-formatter.d.ts +2 -1
- package/typings/plugins/use-schema.d.cts +4 -3
- package/typings/plugins/use-schema.d.ts +4 -3
- package/typings/plugins/use-timing.d.cts +21 -0
- package/typings/plugins/use-timing.d.ts +21 -0
- package/typings/traced-orchestrator.d.cts +7 -0
- package/typings/traced-orchestrator.d.ts +7 -0
- package/typings/traced-schema.d.cts +4 -0
- package/typings/traced-schema.d.ts +4 -0
- package/typings/utils.d.cts +8 -4
- package/typings/utils.d.ts +8 -4
package/cjs/create.js
CHANGED
|
@@ -3,15 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.envelop = void 0;
|
|
4
4
|
const enable_if_js_1 = require("./enable-if.js");
|
|
5
5
|
const orchestrator_js_1 = require("./orchestrator.js");
|
|
6
|
+
const traced_orchestrator_js_1 = require("./traced-orchestrator.js");
|
|
6
7
|
function envelop(options) {
|
|
7
8
|
const plugins = options.plugins.filter(enable_if_js_1.isPluginEnabled);
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
validate: options.validate,
|
|
13
|
-
subscribe: options.subscribe,
|
|
14
|
-
});
|
|
9
|
+
let orchestrator = (0, orchestrator_js_1.createEnvelopOrchestrator)(plugins);
|
|
10
|
+
if (options.enableInternalTracing) {
|
|
11
|
+
orchestrator = (0, traced_orchestrator_js_1.traceOrchestrator)(orchestrator);
|
|
12
|
+
}
|
|
15
13
|
const getEnveloped = (initialContext = {}) => {
|
|
16
14
|
const typedOrchestrator = orchestrator;
|
|
17
15
|
typedOrchestrator.init(initialContext);
|
package/cjs/index.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.resolversHooksSymbol = void 0;
|
|
4
3
|
const tslib_1 = require("tslib");
|
|
5
4
|
tslib_1.__exportStar(require("@envelop/types"), exports);
|
|
6
5
|
tslib_1.__exportStar(require("./create.js"), exports);
|
|
7
6
|
tslib_1.__exportStar(require("./utils.js"), exports);
|
|
8
7
|
tslib_1.__exportStar(require("./plugins/use-envelop.js"), exports);
|
|
9
8
|
tslib_1.__exportStar(require("./plugins/use-logger.js"), exports);
|
|
9
|
+
tslib_1.__exportStar(require("./plugins/use-timing.js"), exports);
|
|
10
10
|
tslib_1.__exportStar(require("./plugins/use-schema.js"), exports);
|
|
11
11
|
tslib_1.__exportStar(require("./plugins/use-error-handler.js"), exports);
|
|
12
12
|
tslib_1.__exportStar(require("./plugins/use-extend-context.js"), exports);
|
|
13
13
|
tslib_1.__exportStar(require("./plugins/use-payload-formatter.js"), exports);
|
|
14
|
+
tslib_1.__exportStar(require("./plugins/use-masked-errors.js"), exports);
|
|
15
|
+
tslib_1.__exportStar(require("./plugins/use-immediate-introspection.js"), exports);
|
|
14
16
|
tslib_1.__exportStar(require("./enable-if.js"), exports);
|
|
15
|
-
var orchestrator_js_1 = require("./orchestrator.js");
|
|
16
|
-
Object.defineProperty(exports, "resolversHooksSymbol", { enumerable: true, get: function () { return orchestrator_js_1.resolversHooksSymbol; } });
|
package/cjs/orchestrator.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createEnvelopOrchestrator =
|
|
3
|
+
exports.createEnvelopOrchestrator = void 0;
|
|
4
|
+
const graphql_1 = require("graphql");
|
|
5
|
+
const traced_schema_js_1 = require("./traced-schema.js");
|
|
4
6
|
const utils_js_1 = require("./utils.js");
|
|
5
|
-
|
|
6
|
-
function createEnvelopOrchestrator({ plugins, parse, execute, subscribe, validate, }) {
|
|
7
|
+
function createEnvelopOrchestrator(plugins) {
|
|
7
8
|
let schema = null;
|
|
8
9
|
let initDone = false;
|
|
9
10
|
const onResolversHandlers = [];
|
|
@@ -17,7 +18,7 @@ function createEnvelopOrchestrator({ plugins, parse, execute, subscribe, validat
|
|
|
17
18
|
// here not to call the same plugin that initiated the schema switch.
|
|
18
19
|
const replaceSchema = (newSchema, ignorePluginIndex = -1) => {
|
|
19
20
|
if (onResolversHandlers.length) {
|
|
20
|
-
|
|
21
|
+
(0, traced_schema_js_1.prepareTracedSchema)(newSchema);
|
|
21
22
|
}
|
|
22
23
|
schema = newSchema;
|
|
23
24
|
if (initDone) {
|
|
@@ -81,7 +82,7 @@ function createEnvelopOrchestrator({ plugins, parse, execute, subscribe, validat
|
|
|
81
82
|
const customParse = beforeCallbacks.parse.length
|
|
82
83
|
? initialContext => (source, parseOptions) => {
|
|
83
84
|
let result = null;
|
|
84
|
-
let parseFn = parse;
|
|
85
|
+
let parseFn = graphql_1.parse;
|
|
85
86
|
const context = initialContext;
|
|
86
87
|
const afterCalls = [];
|
|
87
88
|
for (const onParse of beforeCallbacks.parse) {
|
|
@@ -129,11 +130,11 @@ function createEnvelopOrchestrator({ plugins, parse, execute, subscribe, validat
|
|
|
129
130
|
}
|
|
130
131
|
return result;
|
|
131
132
|
}
|
|
132
|
-
: () => parse;
|
|
133
|
+
: () => graphql_1.parse;
|
|
133
134
|
const customValidate = beforeCallbacks.validate.length
|
|
134
135
|
? initialContext => (schema, documentAST, rules, typeInfo, validationOptions) => {
|
|
135
136
|
let actualRules = rules ? [...rules] : undefined;
|
|
136
|
-
let validateFn = validate;
|
|
137
|
+
let validateFn = graphql_1.validate;
|
|
137
138
|
let result = null;
|
|
138
139
|
const context = initialContext;
|
|
139
140
|
const afterCalls = [];
|
|
@@ -153,10 +154,7 @@ function createEnvelopOrchestrator({ plugins, parse, execute, subscribe, validat
|
|
|
153
154
|
validateFn,
|
|
154
155
|
addValidationRule: rule => {
|
|
155
156
|
if (!actualRules) {
|
|
156
|
-
|
|
157
|
-
// eslint-disable-next-line no-console
|
|
158
|
-
console.warn('No default validation rules provided.');
|
|
159
|
-
actualRules = [];
|
|
157
|
+
actualRules = [...graphql_1.specifiedRules];
|
|
160
158
|
}
|
|
161
159
|
actualRules.push(rule);
|
|
162
160
|
},
|
|
@@ -172,9 +170,6 @@ function createEnvelopOrchestrator({ plugins, parse, execute, subscribe, validat
|
|
|
172
170
|
if (!result) {
|
|
173
171
|
result = validateFn(schema, documentAST, actualRules, typeInfo, validationOptions);
|
|
174
172
|
}
|
|
175
|
-
if (!result) {
|
|
176
|
-
return;
|
|
177
|
-
}
|
|
178
173
|
const valid = result.length === 0;
|
|
179
174
|
for (const afterCb of afterCalls) {
|
|
180
175
|
afterCb({
|
|
@@ -191,7 +186,7 @@ function createEnvelopOrchestrator({ plugins, parse, execute, subscribe, validat
|
|
|
191
186
|
}
|
|
192
187
|
return result;
|
|
193
188
|
}
|
|
194
|
-
: () => validate;
|
|
189
|
+
: () => graphql_1.validate;
|
|
195
190
|
const customContextFactory = beforeCallbacks.context
|
|
196
191
|
.length
|
|
197
192
|
? initialContext => async (orchestratorCtx) => {
|
|
@@ -245,7 +240,7 @@ function createEnvelopOrchestrator({ plugins, parse, execute, subscribe, validat
|
|
|
245
240
|
const useCustomSubscribe = beforeCallbacks.subscribe.length || onResolversHandlers.length;
|
|
246
241
|
const customSubscribe = useCustomSubscribe
|
|
247
242
|
? (0, utils_js_1.makeSubscribe)(async (args) => {
|
|
248
|
-
let subscribeFn = subscribe;
|
|
243
|
+
let subscribeFn = graphql_1.subscribe;
|
|
249
244
|
const afterCalls = [];
|
|
250
245
|
const subscribeErrorHandlers = [];
|
|
251
246
|
let context = args.contextValue || {};
|
|
@@ -277,7 +272,7 @@ function createEnvelopOrchestrator({ plugins, parse, execute, subscribe, validat
|
|
|
277
272
|
}
|
|
278
273
|
}
|
|
279
274
|
if (onResolversHandlers.length) {
|
|
280
|
-
context[
|
|
275
|
+
context[traced_schema_js_1.resolversHooksSymbol] = onResolversHandlers;
|
|
281
276
|
}
|
|
282
277
|
if (result === undefined) {
|
|
283
278
|
result = await subscribeFn({
|
|
@@ -287,9 +282,6 @@ function createEnvelopOrchestrator({ plugins, parse, execute, subscribe, validat
|
|
|
287
282
|
// Can be removed once we drop support for GraphQL.js 15
|
|
288
283
|
});
|
|
289
284
|
}
|
|
290
|
-
if (!result) {
|
|
291
|
-
return;
|
|
292
|
-
}
|
|
293
285
|
const onNextHandler = [];
|
|
294
286
|
const onEndHandler = [];
|
|
295
287
|
for (const afterCb of afterCalls) {
|
|
@@ -344,11 +336,11 @@ function createEnvelopOrchestrator({ plugins, parse, execute, subscribe, validat
|
|
|
344
336
|
}
|
|
345
337
|
return result;
|
|
346
338
|
})
|
|
347
|
-
: (0, utils_js_1.makeSubscribe)(subscribe);
|
|
339
|
+
: (0, utils_js_1.makeSubscribe)(graphql_1.subscribe);
|
|
348
340
|
const useCustomExecute = beforeCallbacks.execute.length || onResolversHandlers.length;
|
|
349
341
|
const customExecute = useCustomExecute
|
|
350
342
|
? (0, utils_js_1.makeExecute)(async (args) => {
|
|
351
|
-
let executeFn = execute;
|
|
343
|
+
let executeFn = graphql_1.execute;
|
|
352
344
|
let result;
|
|
353
345
|
const afterCalls = [];
|
|
354
346
|
let context = args.contextValue || {};
|
|
@@ -382,7 +374,7 @@ function createEnvelopOrchestrator({ plugins, parse, execute, subscribe, validat
|
|
|
382
374
|
}
|
|
383
375
|
}
|
|
384
376
|
if (onResolversHandlers.length) {
|
|
385
|
-
context[
|
|
377
|
+
context[traced_schema_js_1.resolversHooksSymbol] = onResolversHandlers;
|
|
386
378
|
}
|
|
387
379
|
if (result === undefined) {
|
|
388
380
|
result = (await executeFn({
|
|
@@ -432,7 +424,7 @@ function createEnvelopOrchestrator({ plugins, parse, execute, subscribe, validat
|
|
|
432
424
|
}
|
|
433
425
|
return result;
|
|
434
426
|
})
|
|
435
|
-
: (0, utils_js_1.makeExecute)(execute);
|
|
427
|
+
: (0, utils_js_1.makeExecute)(graphql_1.execute);
|
|
436
428
|
initDone = true;
|
|
437
429
|
// This is done in order to trigger the first schema available, to allow plugins that needs the schema
|
|
438
430
|
// eagerly to have it.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useImmediateIntrospection = void 0;
|
|
4
|
+
const graphql_1 = require("graphql");
|
|
5
|
+
const OnNonIntrospectionFieldReachedValidationRule = (onNonIntrospectionField) => ctx => {
|
|
6
|
+
const rootQueryType = ctx.getSchema().getQueryType();
|
|
7
|
+
const rootMutationType = ctx.getSchema().getMutationType();
|
|
8
|
+
const rootSubscriptionType = ctx.getSchema().getSubscriptionType();
|
|
9
|
+
return {
|
|
10
|
+
Field(field) {
|
|
11
|
+
const parentType = ctx.getParentType();
|
|
12
|
+
const isQuery = parentType === rootQueryType;
|
|
13
|
+
const isMutation = parentType === rootMutationType;
|
|
14
|
+
const isSubscription = parentType === rootSubscriptionType;
|
|
15
|
+
if ((isQuery && !field.name.value.startsWith('__')) || isMutation || isSubscription) {
|
|
16
|
+
onNonIntrospectionField();
|
|
17
|
+
return graphql_1.BREAK;
|
|
18
|
+
}
|
|
19
|
+
return undefined;
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
const fastIntroSpectionSymbol = Symbol('fastIntrospection');
|
|
24
|
+
/**
|
|
25
|
+
* In case a GraphQL operation only contains introspection fields the context building can be skipped completely.
|
|
26
|
+
* With this plugin any further context extensions will be skipped.
|
|
27
|
+
*/
|
|
28
|
+
const useImmediateIntrospection = () => {
|
|
29
|
+
return {
|
|
30
|
+
onValidate({ addValidationRule }) {
|
|
31
|
+
let isIntrospectionOnly = true;
|
|
32
|
+
addValidationRule(OnNonIntrospectionFieldReachedValidationRule(() => {
|
|
33
|
+
isIntrospectionOnly = false;
|
|
34
|
+
}));
|
|
35
|
+
return function afterValidate({ extendContext }) {
|
|
36
|
+
if (isIntrospectionOnly) {
|
|
37
|
+
extendContext({ [fastIntroSpectionSymbol]: true });
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
},
|
|
41
|
+
onContextBuilding({ context, breakContextBuilding }) {
|
|
42
|
+
if (context[fastIntroSpectionSymbol]) {
|
|
43
|
+
// hijack and skip all other context related stuff.
|
|
44
|
+
// We dont need a context!
|
|
45
|
+
breakContextBuilding();
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
exports.useImmediateIntrospection = useImmediateIntrospection;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useMaskedErrors = exports.formatError = exports.EnvelopError = exports.DEFAULT_ERROR_MESSAGE = void 0;
|
|
4
|
+
const graphql_1 = require("graphql");
|
|
5
|
+
const utils_js_1 = require("../utils.js");
|
|
6
|
+
exports.DEFAULT_ERROR_MESSAGE = 'Unexpected error.';
|
|
7
|
+
class EnvelopError extends graphql_1.GraphQLError {
|
|
8
|
+
constructor(message, extensions) {
|
|
9
|
+
super(message, undefined, undefined, undefined, undefined, undefined, extensions);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
exports.EnvelopError = EnvelopError;
|
|
13
|
+
const formatError = (err, message, isDev) => {
|
|
14
|
+
var _a, _b, _c, _d;
|
|
15
|
+
if (err instanceof graphql_1.GraphQLError) {
|
|
16
|
+
if (
|
|
17
|
+
/** execution error */
|
|
18
|
+
(err.originalError && err.originalError instanceof EnvelopError === false) ||
|
|
19
|
+
/** validate and parse errors */
|
|
20
|
+
(err.originalError === undefined && err instanceof EnvelopError === false)) {
|
|
21
|
+
return new graphql_1.GraphQLError(message, err.nodes, err.source, err.positions, err.path, undefined, isDev
|
|
22
|
+
? {
|
|
23
|
+
originalError: {
|
|
24
|
+
message: (_b = (_a = err.originalError) === null || _a === void 0 ? void 0 : _a.message) !== null && _b !== void 0 ? _b : err.message,
|
|
25
|
+
stack: (_d = (_c = err.originalError) === null || _c === void 0 ? void 0 : _c.stack) !== null && _d !== void 0 ? _d : err.stack,
|
|
26
|
+
},
|
|
27
|
+
}
|
|
28
|
+
: undefined);
|
|
29
|
+
}
|
|
30
|
+
return err;
|
|
31
|
+
}
|
|
32
|
+
return new graphql_1.GraphQLError(message);
|
|
33
|
+
};
|
|
34
|
+
exports.formatError = formatError;
|
|
35
|
+
const makeHandleResult = (format, message, isDev) => ({ result, setResult }) => {
|
|
36
|
+
if (result.errors != null) {
|
|
37
|
+
setResult({ ...result, errors: result.errors.map(error => format(error, message, isDev)) });
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
const useMaskedErrors = (opts) => {
|
|
41
|
+
var _a, _b;
|
|
42
|
+
const format = (_a = opts === null || opts === void 0 ? void 0 : opts.formatError) !== null && _a !== void 0 ? _a : exports.formatError;
|
|
43
|
+
const message = (opts === null || opts === void 0 ? void 0 : opts.errorMessage) || exports.DEFAULT_ERROR_MESSAGE;
|
|
44
|
+
// eslint-disable-next-line dot-notation
|
|
45
|
+
const isDev = (_b = opts === null || opts === void 0 ? void 0 : opts.isDev) !== null && _b !== void 0 ? _b : (typeof process !== 'undefined' ? process.env['NODE_ENV'] === 'development' : false);
|
|
46
|
+
const handleResult = makeHandleResult(format, message, isDev);
|
|
47
|
+
return {
|
|
48
|
+
onParse: (opts === null || opts === void 0 ? void 0 : opts.handleParseErrors) === true
|
|
49
|
+
? function onParse() {
|
|
50
|
+
return function onParseEnd({ result, replaceParseResult }) {
|
|
51
|
+
if (result instanceof Error) {
|
|
52
|
+
replaceParseResult(format(result, message, isDev));
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
: undefined,
|
|
57
|
+
onValidate: (opts === null || opts === void 0 ? void 0 : opts.handleValidationErrors) === true
|
|
58
|
+
? function onValidate() {
|
|
59
|
+
return function onValidateEnd({ valid, result, setResult }) {
|
|
60
|
+
if (valid === false) {
|
|
61
|
+
setResult(result.map(error => format(error, message, isDev)));
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
: undefined,
|
|
66
|
+
onPluginInit(context) {
|
|
67
|
+
context.registerContextErrorHandler(({ error, setError }) => {
|
|
68
|
+
if (error instanceof graphql_1.GraphQLError === false && error instanceof Error) {
|
|
69
|
+
error = new graphql_1.GraphQLError(error.message, undefined, undefined, undefined, undefined, error);
|
|
70
|
+
}
|
|
71
|
+
setError(format(error, message, isDev));
|
|
72
|
+
});
|
|
73
|
+
},
|
|
74
|
+
onExecute() {
|
|
75
|
+
return {
|
|
76
|
+
onExecuteDone(payload) {
|
|
77
|
+
return (0, utils_js_1.handleStreamOrSingleExecutionResult)(payload, handleResult);
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
},
|
|
81
|
+
onSubscribe() {
|
|
82
|
+
return {
|
|
83
|
+
onSubscribeResult(payload) {
|
|
84
|
+
return (0, utils_js_1.handleStreamOrSingleExecutionResult)(payload, handleResult);
|
|
85
|
+
},
|
|
86
|
+
onSubscribeError({ error, setError }) {
|
|
87
|
+
setError(format(error, message, isDev));
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
exports.useMaskedErrors = useMaskedErrors;
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useTiming = void 0;
|
|
4
|
+
const graphql_1 = require("graphql");
|
|
5
|
+
const utils_js_1 = require("../utils.js");
|
|
6
|
+
const HR_TO_NS = 1e9;
|
|
7
|
+
const NS_TO_MS = 1e6;
|
|
8
|
+
const DEFAULT_OPTIONS = {
|
|
9
|
+
onExecutionMeasurement: (args, timing) => console.log(`Operation execution "${args.operationName}" done in ${timing.ms}ms`),
|
|
10
|
+
onSubscriptionMeasurement: (args, timing) => console.log(`Operation subscription "${args.operationName}" done in ${timing.ms}ms`),
|
|
11
|
+
onParsingMeasurement: (source, timing) => console.log(`Parsing "${source}" done in ${timing.ms}ms`),
|
|
12
|
+
onValidationMeasurement: (document, timing) => { var _a, _b; return console.log(`Validation "${((_b = (_a = (0, graphql_1.getOperationAST)(document)) === null || _a === void 0 ? void 0 : _a.name) === null || _b === void 0 ? void 0 : _b.value) || '-'}" done in ${timing.ms}ms`); },
|
|
13
|
+
onResolverMeasurement: (info, timing) => console.log(`\tResolver of "${info.parentType.toString()}.${info.fieldName}" done in ${timing.ms}ms`),
|
|
14
|
+
onContextBuildingMeasurement: (timing) => console.log(`Context building done in ${timing.ms}ms`),
|
|
15
|
+
};
|
|
16
|
+
const deltaFrom = (hrtime) => {
|
|
17
|
+
const delta = process.hrtime(hrtime);
|
|
18
|
+
const ns = delta[0] * HR_TO_NS + delta[1];
|
|
19
|
+
return {
|
|
20
|
+
ns,
|
|
21
|
+
get ms() {
|
|
22
|
+
return ns / NS_TO_MS;
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
const useTiming = (rawOptions) => {
|
|
27
|
+
const options = {
|
|
28
|
+
...DEFAULT_OPTIONS,
|
|
29
|
+
...rawOptions,
|
|
30
|
+
};
|
|
31
|
+
const result = {};
|
|
32
|
+
if (options.onContextBuildingMeasurement) {
|
|
33
|
+
result.onContextBuilding = ({ context }) => {
|
|
34
|
+
if (context[utils_js_1.envelopIsIntrospectionSymbol]) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const contextStartTime = process.hrtime();
|
|
38
|
+
return () => {
|
|
39
|
+
options.onContextBuildingMeasurement(deltaFrom(contextStartTime));
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
if (options.onParsingMeasurement) {
|
|
44
|
+
result.onParse = ({ params, extendContext }) => {
|
|
45
|
+
if (options.skipIntrospection && (0, utils_js_1.isIntrospectionOperationString)(params.source)) {
|
|
46
|
+
extendContext({
|
|
47
|
+
[utils_js_1.envelopIsIntrospectionSymbol]: true,
|
|
48
|
+
});
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const parseStartTime = process.hrtime();
|
|
52
|
+
return () => {
|
|
53
|
+
options.onParsingMeasurement(params.source, deltaFrom(parseStartTime));
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
if (options.onValidationMeasurement) {
|
|
58
|
+
result.onValidate = ({ params, context }) => {
|
|
59
|
+
if (context[utils_js_1.envelopIsIntrospectionSymbol]) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const validateStartTime = process.hrtime();
|
|
63
|
+
return () => {
|
|
64
|
+
options.onValidationMeasurement(params.documentAST, deltaFrom(validateStartTime));
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
if (options.onExecutionMeasurement) {
|
|
69
|
+
if (options.onResolverMeasurement) {
|
|
70
|
+
result.onExecute = ({ args }) => {
|
|
71
|
+
if (args.contextValue[utils_js_1.envelopIsIntrospectionSymbol]) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const executeStartTime = process.hrtime();
|
|
75
|
+
return {
|
|
76
|
+
onExecuteDone: () => {
|
|
77
|
+
options.onExecutionMeasurement(args, deltaFrom(executeStartTime));
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
result.onResolverCalled = ({ info }) => {
|
|
82
|
+
const resolverStartTime = process.hrtime();
|
|
83
|
+
return () => {
|
|
84
|
+
options.onResolverMeasurement(info, deltaFrom(resolverStartTime));
|
|
85
|
+
};
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
result.onExecute = ({ args }) => {
|
|
90
|
+
if (args.contextValue[utils_js_1.envelopIsIntrospectionSymbol]) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const executeStartTime = process.hrtime();
|
|
94
|
+
return {
|
|
95
|
+
onExecuteDone: () => {
|
|
96
|
+
options.onExecutionMeasurement(args, deltaFrom(executeStartTime));
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (options.onSubscriptionMeasurement) {
|
|
103
|
+
if (options.onResolverMeasurement) {
|
|
104
|
+
result.onSubscribe = ({ args }) => {
|
|
105
|
+
if (args.contextValue[utils_js_1.envelopIsIntrospectionSymbol]) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
const subscribeStartTime = process.hrtime();
|
|
109
|
+
return {
|
|
110
|
+
onSubscribeResult: () => {
|
|
111
|
+
options.onSubscriptionMeasurement && options.onSubscriptionMeasurement(args, deltaFrom(subscribeStartTime));
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
};
|
|
115
|
+
result.onResolverCalled = ({ info }) => {
|
|
116
|
+
const resolverStartTime = process.hrtime();
|
|
117
|
+
return () => {
|
|
118
|
+
options.onResolverMeasurement && options.onResolverMeasurement(info, deltaFrom(resolverStartTime));
|
|
119
|
+
};
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
result.onSubscribe = ({ args }) => {
|
|
124
|
+
if (args.contextValue[utils_js_1.envelopIsIntrospectionSymbol]) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
const subscribeStartTime = process.hrtime();
|
|
128
|
+
return {
|
|
129
|
+
onSubscribeResult: () => {
|
|
130
|
+
options.onSubscriptionMeasurement && options.onSubscriptionMeasurement(args, deltaFrom(subscribeStartTime));
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return result;
|
|
137
|
+
};
|
|
138
|
+
exports.useTiming = useTiming;
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var _a;
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.traceOrchestrator = void 0;
|
|
5
|
+
const graphql_1 = require("graphql");
|
|
6
|
+
const utils_js_1 = require("./utils.js");
|
|
7
|
+
const getTimestamp = typeof globalThis !== 'undefined' && ((_a = globalThis === null || globalThis === void 0 ? void 0 : globalThis.performance) === null || _a === void 0 ? void 0 : _a.now)
|
|
8
|
+
? () => globalThis.performance.now()
|
|
9
|
+
: () => Date.now();
|
|
10
|
+
const measure = () => {
|
|
11
|
+
const start = getTimestamp();
|
|
12
|
+
return () => {
|
|
13
|
+
const end = getTimestamp();
|
|
14
|
+
return end - start;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
const tracingSymbol = Symbol('envelopTracing');
|
|
18
|
+
function traceOrchestrator(orchestrator) {
|
|
19
|
+
const createTracer = (name, ctx) => {
|
|
20
|
+
const end = measure();
|
|
21
|
+
return () => {
|
|
22
|
+
ctx[tracingSymbol][name] = end();
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
return {
|
|
26
|
+
...orchestrator,
|
|
27
|
+
init: (ctx = {}) => {
|
|
28
|
+
ctx[tracingSymbol] = ctx[tracingSymbol] || {};
|
|
29
|
+
const done = createTracer('init', ctx || {});
|
|
30
|
+
try {
|
|
31
|
+
return orchestrator.init(ctx);
|
|
32
|
+
}
|
|
33
|
+
finally {
|
|
34
|
+
done();
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
parse: (ctx = {}) => {
|
|
38
|
+
ctx[tracingSymbol] = ctx[tracingSymbol] || {};
|
|
39
|
+
const actualFn = orchestrator.parse(ctx);
|
|
40
|
+
return (...args) => {
|
|
41
|
+
const done = createTracer('parse', ctx);
|
|
42
|
+
try {
|
|
43
|
+
return actualFn(...args);
|
|
44
|
+
}
|
|
45
|
+
finally {
|
|
46
|
+
done();
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
},
|
|
50
|
+
validate: (ctx = {}) => {
|
|
51
|
+
ctx[tracingSymbol] = ctx[tracingSymbol] || {};
|
|
52
|
+
const actualFn = orchestrator.validate(ctx);
|
|
53
|
+
return (...args) => {
|
|
54
|
+
const done = createTracer('validate', ctx);
|
|
55
|
+
try {
|
|
56
|
+
return actualFn(...args);
|
|
57
|
+
}
|
|
58
|
+
finally {
|
|
59
|
+
done();
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
},
|
|
63
|
+
execute: async (argsOrSchema, document, rootValue, contextValue, variableValues, operationName, fieldResolver, typeResolver) => {
|
|
64
|
+
const args = argsOrSchema instanceof graphql_1.GraphQLSchema
|
|
65
|
+
? {
|
|
66
|
+
schema: argsOrSchema,
|
|
67
|
+
document: document,
|
|
68
|
+
rootValue,
|
|
69
|
+
contextValue,
|
|
70
|
+
variableValues,
|
|
71
|
+
operationName,
|
|
72
|
+
fieldResolver,
|
|
73
|
+
typeResolver,
|
|
74
|
+
}
|
|
75
|
+
: argsOrSchema;
|
|
76
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
77
|
+
// @ts-ignore GraphQL.js types contextValue as unknown
|
|
78
|
+
const done = createTracer('execute', args.contextValue || {});
|
|
79
|
+
try {
|
|
80
|
+
const result = await orchestrator.execute(args);
|
|
81
|
+
done();
|
|
82
|
+
if (!(0, utils_js_1.isAsyncIterable)(result)) {
|
|
83
|
+
result.extensions = result.extensions || {};
|
|
84
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
85
|
+
// @ts-ignore GraphQL.js types contextValue as unknown
|
|
86
|
+
result.extensions.envelopTracing = args.contextValue[tracingSymbol];
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
// eslint-disable-next-line no-console
|
|
90
|
+
console.warn(`"traceOrchestrator" encountered a AsyncIterator which is not supported yet, so tracing data is not available for the operation.`);
|
|
91
|
+
}
|
|
92
|
+
return result;
|
|
93
|
+
}
|
|
94
|
+
catch (e) {
|
|
95
|
+
done();
|
|
96
|
+
throw e;
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
subscribe: async (argsOrSchema, document, rootValue, contextValue, variableValues, operationName, fieldResolver, subscribeFieldResolver) => {
|
|
100
|
+
const args = argsOrSchema instanceof graphql_1.GraphQLSchema
|
|
101
|
+
? {
|
|
102
|
+
schema: argsOrSchema,
|
|
103
|
+
document: document,
|
|
104
|
+
rootValue,
|
|
105
|
+
contextValue,
|
|
106
|
+
variableValues,
|
|
107
|
+
operationName,
|
|
108
|
+
fieldResolver,
|
|
109
|
+
subscribeFieldResolver,
|
|
110
|
+
}
|
|
111
|
+
: argsOrSchema;
|
|
112
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
113
|
+
// @ts-ignore GraphQL.js types contextValue as unknown
|
|
114
|
+
const done = createTracer('subscribe', args.contextValue || {});
|
|
115
|
+
try {
|
|
116
|
+
return await orchestrator.subscribe(args);
|
|
117
|
+
}
|
|
118
|
+
finally {
|
|
119
|
+
done();
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
contextFactory: (ctx = {}) => {
|
|
123
|
+
const actualFn = orchestrator.contextFactory(ctx);
|
|
124
|
+
return async (childCtx) => {
|
|
125
|
+
const done = createTracer('contextFactory', ctx);
|
|
126
|
+
try {
|
|
127
|
+
return await actualFn(childCtx);
|
|
128
|
+
}
|
|
129
|
+
finally {
|
|
130
|
+
done();
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
exports.traceOrchestrator = traceOrchestrator;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.prepareTracedSchema = exports.resolversHooksSymbol = exports.trackedSchemaSymbol = void 0;
|
|
4
|
+
const graphql_1 = require("graphql");
|
|
5
|
+
exports.trackedSchemaSymbol = Symbol('TRACKED_SCHEMA');
|
|
6
|
+
exports.resolversHooksSymbol = Symbol('RESOLVERS_HOOKS');
|
|
7
|
+
function prepareTracedSchema(schema) {
|
|
8
|
+
if (!schema || schema[exports.trackedSchemaSymbol]) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
schema[exports.trackedSchemaSymbol] = true;
|
|
12
|
+
const entries = Object.values(schema.getTypeMap());
|
|
13
|
+
for (const type of entries) {
|
|
14
|
+
if (!(0, graphql_1.isIntrospectionType)(type) && (0, graphql_1.isObjectType)(type)) {
|
|
15
|
+
const fields = Object.values(type.getFields());
|
|
16
|
+
for (const field of fields) {
|
|
17
|
+
let resolverFn = (field.resolve || graphql_1.defaultFieldResolver);
|
|
18
|
+
field.resolve = async (root, args, context, info) => {
|
|
19
|
+
if (context && context[exports.resolversHooksSymbol]) {
|
|
20
|
+
const hooks = context[exports.resolversHooksSymbol];
|
|
21
|
+
const afterCalls = [];
|
|
22
|
+
for (const hook of hooks) {
|
|
23
|
+
const afterFn = await hook({
|
|
24
|
+
root,
|
|
25
|
+
args,
|
|
26
|
+
context,
|
|
27
|
+
info,
|
|
28
|
+
resolverFn,
|
|
29
|
+
replaceResolverFn: newFn => {
|
|
30
|
+
resolverFn = newFn;
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
afterFn && afterCalls.push(afterFn);
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
let result = await resolverFn(root, args, context, info);
|
|
37
|
+
for (const afterFn of afterCalls) {
|
|
38
|
+
afterFn({
|
|
39
|
+
result,
|
|
40
|
+
setResult: newResult => {
|
|
41
|
+
result = newResult;
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
return result;
|
|
46
|
+
}
|
|
47
|
+
catch (e) {
|
|
48
|
+
let resultErr = e;
|
|
49
|
+
for (const afterFn of afterCalls) {
|
|
50
|
+
afterFn({
|
|
51
|
+
result: resultErr,
|
|
52
|
+
setResult: newResult => {
|
|
53
|
+
resultErr = newResult;
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
throw resultErr;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
return resolverFn(root, args, context, info);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
exports.prepareTracedSchema = prepareTracedSchema;
|