@graphql-yoga/plugin-apollo-usage-report 0.9.0-alpha-20250516145220-f0c0edf8042caaad772e2ada1ef90d4b16ff82f8 → 0.9.0-alpha-20250527093154-d0be5f4626600bfbe255c0ab57590d3963013823
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/index.js +21 -17
- package/cjs/reporter.js +12 -15
- package/esm/index.js +22 -18
- package/esm/reporter.js +12 -15
- package/package.json +4 -3
package/cjs/index.js
CHANGED
|
@@ -5,12 +5,13 @@ exports.hashSHA256 = hashSHA256;
|
|
|
5
5
|
const graphql_1 = require("graphql");
|
|
6
6
|
const graphql_yoga_1 = require("graphql-yoga");
|
|
7
7
|
const utils_usagereporting_1 = require("@apollo/utils.usagereporting");
|
|
8
|
+
const utils_1 = require("@graphql-tools/utils");
|
|
8
9
|
const plugin_apollo_inline_trace_1 = require("@graphql-yoga/plugin-apollo-inline-trace");
|
|
9
10
|
const reporter_js_1 = require("./reporter.js");
|
|
10
11
|
function useApolloUsageReport(options = {}) {
|
|
11
12
|
const [instrumentation, ctxForReq] = (0, plugin_apollo_inline_trace_1.useApolloInstrumentation)(options);
|
|
12
13
|
let schemaIdSet$;
|
|
13
|
-
let
|
|
14
|
+
let currentSchema;
|
|
14
15
|
let yoga;
|
|
15
16
|
let reporter;
|
|
16
17
|
const logger = Object.fromEntries(['error', 'warn', 'info', 'debug'].map(level => [
|
|
@@ -41,9 +42,9 @@ function useApolloUsageReport(options = {}) {
|
|
|
41
42
|
},
|
|
42
43
|
onSchemaChange({ schema }) {
|
|
43
44
|
if (schema) {
|
|
44
|
-
schemaIdSet$ = hashSHA256((0,
|
|
45
|
+
schemaIdSet$ = hashSHA256((0, utils_1.printSchemaWithDirectives)(schema), yoga.fetchAPI)
|
|
45
46
|
.then(id => {
|
|
46
|
-
|
|
47
|
+
currentSchema = { id, schema };
|
|
47
48
|
schemaIdSet$ = undefined;
|
|
48
49
|
})
|
|
49
50
|
.catch(error => {
|
|
@@ -56,7 +57,7 @@ function useApolloUsageReport(options = {}) {
|
|
|
56
57
|
},
|
|
57
58
|
onParse() {
|
|
58
59
|
return function onParseEnd({ result, context }) {
|
|
59
|
-
if (!
|
|
60
|
+
if (!currentSchema) {
|
|
60
61
|
throw new Error("should not happen: schema doesn't exists");
|
|
61
62
|
}
|
|
62
63
|
const ctx = ctxForReq.get(context.request)?.traces.get(context);
|
|
@@ -64,18 +65,21 @@ function useApolloUsageReport(options = {}) {
|
|
|
64
65
|
logger.debug('operation tracing context not found, this operation will not be traced.');
|
|
65
66
|
return;
|
|
66
67
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
68
|
+
ctx.schemaId = currentSchema.id;
|
|
69
|
+
// It is possible that the result is not a document when the parsing fails
|
|
70
|
+
const document = isDocumentNode(result) ? result : null;
|
|
71
|
+
if (document) {
|
|
72
|
+
const opName = (0, graphql_1.getOperationAST)(document, context.params.operationName)?.name?.value;
|
|
73
|
+
ctx.referencedFieldsByType = (0, utils_usagereporting_1.calculateReferencedFieldsByType)({
|
|
74
|
+
document,
|
|
75
|
+
schema: currentSchema.schema,
|
|
76
|
+
resolvedOperationName: opName ?? null,
|
|
77
|
+
});
|
|
78
|
+
ctx.operationKey = `# ${opName || '-'}\n${opName && (0, utils_usagereporting_1.usageReportingSignature)(document, opName)}`;
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
ctx.operationKey = `# ${context.params.operationName || '-'} \n${context.params.query ?? ''}`;
|
|
82
|
+
}
|
|
79
83
|
};
|
|
80
84
|
},
|
|
81
85
|
onResultProcess({ request, result, serverContext }) {
|
|
@@ -102,7 +106,7 @@ function useApolloUsageReport(options = {}) {
|
|
|
102
106
|
if (clientVersion) {
|
|
103
107
|
trace.trace.clientVersion = clientVersion;
|
|
104
108
|
}
|
|
105
|
-
serverContext.waitUntil(reporter.addTrace(
|
|
109
|
+
serverContext.waitUntil(reporter.addTrace(currentSchema.id, {
|
|
106
110
|
statsReportKey: trace.operationKey,
|
|
107
111
|
trace: trace.trace,
|
|
108
112
|
referencedFieldsByType: trace.referencedFieldsByType,
|
package/cjs/reporter.js
CHANGED
|
@@ -19,10 +19,10 @@ class Reporter {
|
|
|
19
19
|
this.#yoga = yoga;
|
|
20
20
|
this.#options = {
|
|
21
21
|
...options,
|
|
22
|
-
maxBatchDelay: options.maxBatchDelay ??
|
|
22
|
+
maxBatchDelay: options.maxBatchDelay ?? 20_000, // 20s
|
|
23
23
|
maxBatchUncompressedSize: options.maxBatchUncompressedSize ?? 4 * 1024 * 1024, // 4mb
|
|
24
24
|
maxTraceSize: options.maxTraceSize ?? 10 * 1024 * 1024, // 10mb
|
|
25
|
-
exportTimeout: options.exportTimeout ??
|
|
25
|
+
exportTimeout: options.exportTimeout ?? 30_000, // 30s
|
|
26
26
|
};
|
|
27
27
|
this.#reportHeaders = {
|
|
28
28
|
graphRef: getGraphRef(options),
|
|
@@ -62,27 +62,20 @@ class Reporter {
|
|
|
62
62
|
}
|
|
63
63
|
if (this.#nextSendAfterDelay != null) {
|
|
64
64
|
clearTimeout(this.#nextSendAfterDelay);
|
|
65
|
+
this.#nextSendAfterDelay = undefined;
|
|
65
66
|
}
|
|
66
67
|
delete this.#reportsBySchema[schemaId];
|
|
67
68
|
report.endTime = dateToProtoTimestamp(new Date());
|
|
68
69
|
report.ensureCountsAreIntegers();
|
|
69
70
|
const validationError = usage_reporting_protobuf_1.Report.verify(report);
|
|
70
|
-
if (
|
|
71
|
+
if (validationError) {
|
|
71
72
|
throw new TypeError(`Invalid report: ${validationError}`);
|
|
72
73
|
}
|
|
73
|
-
const encodedReport = usage_reporting_protobuf_1.Report.encode(report).finish();
|
|
74
|
-
const compressedReport = new ReadableStream({
|
|
75
|
-
start(controller) {
|
|
76
|
-
controller.enqueue(encodedReport);
|
|
77
|
-
controller.close();
|
|
78
|
-
},
|
|
79
|
-
}).pipeThrough(new CompressionStream('gzip'));
|
|
80
74
|
const { apiKey = getEnvVar('APOLLO_KEY'), endpoint = DEFAULT_REPORTING_ENDPOINT } = this.#options;
|
|
75
|
+
const encodedReport = usage_reporting_protobuf_1.Report.encode(report).finish();
|
|
81
76
|
for (let tries = 0; tries < 5; tries++) {
|
|
82
77
|
try {
|
|
83
|
-
const abortCtl = new AbortController();
|
|
84
78
|
this.#logger?.debug(`Sending report (try ${tries}/5)`);
|
|
85
|
-
const timeout = setTimeout(() => abortCtl.abort(), this.#options.exportTimeout);
|
|
86
79
|
const response = await fetch(endpoint, {
|
|
87
80
|
method: 'POST',
|
|
88
81
|
headers: {
|
|
@@ -92,10 +85,14 @@ class Reporter {
|
|
|
92
85
|
'x-api-key': apiKey,
|
|
93
86
|
accept: 'application/json',
|
|
94
87
|
},
|
|
95
|
-
body:
|
|
96
|
-
|
|
88
|
+
body: new ReadableStream({
|
|
89
|
+
start(controller) {
|
|
90
|
+
controller.enqueue(encodedReport);
|
|
91
|
+
controller.close();
|
|
92
|
+
},
|
|
93
|
+
}).pipeThrough(new CompressionStream('gzip')),
|
|
94
|
+
signal: AbortSignal.timeout(this.#options.exportTimeout),
|
|
97
95
|
});
|
|
98
|
-
clearTimeout(timeout);
|
|
99
96
|
const result = await response.text();
|
|
100
97
|
if (response.ok) {
|
|
101
98
|
this.#logger?.debug('Report sent:', result);
|
package/esm/index.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { getOperationAST, Kind
|
|
1
|
+
import { getOperationAST, Kind } from 'graphql';
|
|
2
2
|
import { isAsyncIterable, } from 'graphql-yoga';
|
|
3
3
|
import { calculateReferencedFieldsByType, usageReportingSignature, } from '@apollo/utils.usagereporting';
|
|
4
|
+
import { printSchemaWithDirectives } from '@graphql-tools/utils';
|
|
4
5
|
import { useApolloInstrumentation, } from '@graphql-yoga/plugin-apollo-inline-trace';
|
|
5
6
|
import { getEnvVar, Reporter } from './reporter.js';
|
|
6
7
|
export function useApolloUsageReport(options = {}) {
|
|
7
8
|
const [instrumentation, ctxForReq] = useApolloInstrumentation(options);
|
|
8
9
|
let schemaIdSet$;
|
|
9
|
-
let
|
|
10
|
+
let currentSchema;
|
|
10
11
|
let yoga;
|
|
11
12
|
let reporter;
|
|
12
13
|
const logger = Object.fromEntries(['error', 'warn', 'info', 'debug'].map(level => [
|
|
@@ -37,9 +38,9 @@ export function useApolloUsageReport(options = {}) {
|
|
|
37
38
|
},
|
|
38
39
|
onSchemaChange({ schema }) {
|
|
39
40
|
if (schema) {
|
|
40
|
-
schemaIdSet$ = hashSHA256(
|
|
41
|
+
schemaIdSet$ = hashSHA256(printSchemaWithDirectives(schema), yoga.fetchAPI)
|
|
41
42
|
.then(id => {
|
|
42
|
-
|
|
43
|
+
currentSchema = { id, schema };
|
|
43
44
|
schemaIdSet$ = undefined;
|
|
44
45
|
})
|
|
45
46
|
.catch(error => {
|
|
@@ -52,7 +53,7 @@ export function useApolloUsageReport(options = {}) {
|
|
|
52
53
|
},
|
|
53
54
|
onParse() {
|
|
54
55
|
return function onParseEnd({ result, context }) {
|
|
55
|
-
if (!
|
|
56
|
+
if (!currentSchema) {
|
|
56
57
|
throw new Error("should not happen: schema doesn't exists");
|
|
57
58
|
}
|
|
58
59
|
const ctx = ctxForReq.get(context.request)?.traces.get(context);
|
|
@@ -60,18 +61,21 @@ export function useApolloUsageReport(options = {}) {
|
|
|
60
61
|
logger.debug('operation tracing context not found, this operation will not be traced.');
|
|
61
62
|
return;
|
|
62
63
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
64
|
+
ctx.schemaId = currentSchema.id;
|
|
65
|
+
// It is possible that the result is not a document when the parsing fails
|
|
66
|
+
const document = isDocumentNode(result) ? result : null;
|
|
67
|
+
if (document) {
|
|
68
|
+
const opName = getOperationAST(document, context.params.operationName)?.name?.value;
|
|
69
|
+
ctx.referencedFieldsByType = calculateReferencedFieldsByType({
|
|
70
|
+
document,
|
|
71
|
+
schema: currentSchema.schema,
|
|
72
|
+
resolvedOperationName: opName ?? null,
|
|
73
|
+
});
|
|
74
|
+
ctx.operationKey = `# ${opName || '-'}\n${opName && usageReportingSignature(document, opName)}`;
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
ctx.operationKey = `# ${context.params.operationName || '-'} \n${context.params.query ?? ''}`;
|
|
78
|
+
}
|
|
75
79
|
};
|
|
76
80
|
},
|
|
77
81
|
onResultProcess({ request, result, serverContext }) {
|
|
@@ -98,7 +102,7 @@ export function useApolloUsageReport(options = {}) {
|
|
|
98
102
|
if (clientVersion) {
|
|
99
103
|
trace.trace.clientVersion = clientVersion;
|
|
100
104
|
}
|
|
101
|
-
serverContext.waitUntil(reporter.addTrace(
|
|
105
|
+
serverContext.waitUntil(reporter.addTrace(currentSchema.id, {
|
|
102
106
|
statsReportKey: trace.operationKey,
|
|
103
107
|
trace: trace.trace,
|
|
104
108
|
referencedFieldsByType: trace.referencedFieldsByType,
|
package/esm/reporter.js
CHANGED
|
@@ -14,10 +14,10 @@ export class Reporter {
|
|
|
14
14
|
this.#yoga = yoga;
|
|
15
15
|
this.#options = {
|
|
16
16
|
...options,
|
|
17
|
-
maxBatchDelay: options.maxBatchDelay ??
|
|
17
|
+
maxBatchDelay: options.maxBatchDelay ?? 20_000, // 20s
|
|
18
18
|
maxBatchUncompressedSize: options.maxBatchUncompressedSize ?? 4 * 1024 * 1024, // 4mb
|
|
19
19
|
maxTraceSize: options.maxTraceSize ?? 10 * 1024 * 1024, // 10mb
|
|
20
|
-
exportTimeout: options.exportTimeout ??
|
|
20
|
+
exportTimeout: options.exportTimeout ?? 30_000, // 30s
|
|
21
21
|
};
|
|
22
22
|
this.#reportHeaders = {
|
|
23
23
|
graphRef: getGraphRef(options),
|
|
@@ -57,27 +57,20 @@ export class Reporter {
|
|
|
57
57
|
}
|
|
58
58
|
if (this.#nextSendAfterDelay != null) {
|
|
59
59
|
clearTimeout(this.#nextSendAfterDelay);
|
|
60
|
+
this.#nextSendAfterDelay = undefined;
|
|
60
61
|
}
|
|
61
62
|
delete this.#reportsBySchema[schemaId];
|
|
62
63
|
report.endTime = dateToProtoTimestamp(new Date());
|
|
63
64
|
report.ensureCountsAreIntegers();
|
|
64
65
|
const validationError = Report.verify(report);
|
|
65
|
-
if (
|
|
66
|
+
if (validationError) {
|
|
66
67
|
throw new TypeError(`Invalid report: ${validationError}`);
|
|
67
68
|
}
|
|
68
|
-
const encodedReport = Report.encode(report).finish();
|
|
69
|
-
const compressedReport = new ReadableStream({
|
|
70
|
-
start(controller) {
|
|
71
|
-
controller.enqueue(encodedReport);
|
|
72
|
-
controller.close();
|
|
73
|
-
},
|
|
74
|
-
}).pipeThrough(new CompressionStream('gzip'));
|
|
75
69
|
const { apiKey = getEnvVar('APOLLO_KEY'), endpoint = DEFAULT_REPORTING_ENDPOINT } = this.#options;
|
|
70
|
+
const encodedReport = Report.encode(report).finish();
|
|
76
71
|
for (let tries = 0; tries < 5; tries++) {
|
|
77
72
|
try {
|
|
78
|
-
const abortCtl = new AbortController();
|
|
79
73
|
this.#logger?.debug(`Sending report (try ${tries}/5)`);
|
|
80
|
-
const timeout = setTimeout(() => abortCtl.abort(), this.#options.exportTimeout);
|
|
81
74
|
const response = await fetch(endpoint, {
|
|
82
75
|
method: 'POST',
|
|
83
76
|
headers: {
|
|
@@ -87,10 +80,14 @@ export class Reporter {
|
|
|
87
80
|
'x-api-key': apiKey,
|
|
88
81
|
accept: 'application/json',
|
|
89
82
|
},
|
|
90
|
-
body:
|
|
91
|
-
|
|
83
|
+
body: new ReadableStream({
|
|
84
|
+
start(controller) {
|
|
85
|
+
controller.enqueue(encodedReport);
|
|
86
|
+
controller.close();
|
|
87
|
+
},
|
|
88
|
+
}).pipeThrough(new CompressionStream('gzip')),
|
|
89
|
+
signal: AbortSignal.timeout(this.#options.exportTimeout),
|
|
92
90
|
});
|
|
93
|
-
clearTimeout(timeout);
|
|
94
91
|
const result = await response.text();
|
|
95
92
|
if (response.ok) {
|
|
96
93
|
this.#logger?.debug('Report sent:', result);
|
package/package.json
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@graphql-yoga/plugin-apollo-usage-report",
|
|
3
|
-
"version": "0.9.0-alpha-
|
|
3
|
+
"version": "0.9.0-alpha-20250527093154-d0be5f4626600bfbe255c0ab57590d3963013823",
|
|
4
4
|
"description": "Apollo's GraphOS usage report plugin for GraphQL Yoga.",
|
|
5
5
|
"peerDependencies": {
|
|
6
6
|
"graphql": "^15.2.0 || ^16.0.0",
|
|
7
|
-
"graphql-yoga": "^5.13.
|
|
7
|
+
"graphql-yoga": "^5.13.5"
|
|
8
8
|
},
|
|
9
9
|
"dependencies": {
|
|
10
10
|
"@apollo/server-gateway-interface": "^1.1.1",
|
|
11
11
|
"@apollo/usage-reporting-protobuf": "^4.1.1",
|
|
12
12
|
"@apollo/utils.usagereporting": "^2.1.0",
|
|
13
|
+
"@graphql-tools/utils": "^10.8.6",
|
|
13
14
|
"@whatwg-node/promise-helpers": "^1.2.4",
|
|
14
15
|
"tslib": "^2.8.1",
|
|
15
|
-
"@graphql-yoga/plugin-apollo-inline-trace": "^3.13.
|
|
16
|
+
"@graphql-yoga/plugin-apollo-inline-trace": "^3.13.5"
|
|
16
17
|
},
|
|
17
18
|
"repository": {
|
|
18
19
|
"type": "git",
|