Skip to content

Commit

Permalink
Make @apollo/usage-reporting-protobuf dual CJS/ESM too
Browse files Browse the repository at this point in the history
This mostly involved running pbjs a second time to generate ESM. A few
tweaks were made to our fork `@apollo/protobufjs`:
- Long support is just turned off by default, so we don't need the
  wrapper index.* files that just turn it off
- The import line in generated code no longer includes `* as` since that
  didn't quite work in practice (it imported an object with a 'default'
  key on it)
- The `@apollo/protobufjs` package.json uses `exports` to show where
  `/minimal` is
  • Loading branch information
glasser committed Jun 16, 2022
1 parent 1389f4f commit 64b2d63
Show file tree
Hide file tree
Showing 14 changed files with 7,341 additions and 228 deletions.
61 changes: 59 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions packages/server/src/plugin/inlineTrace/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import proto from '@apollo/usage-reporting-protobuf';
import { Trace } from '@apollo/usage-reporting-protobuf';
import { TraceTreeBuilder } from '../traceTreeBuilder.js';
import type { ApolloServerPluginUsageReportingOptions } from '../usageReporting/options';
import type { InternalApolloServerPlugin } from '../../internalPlugin';
import { schemaIsFederated } from '../schemaIsFederated.js';
import type { BaseContext } from '../../externalTypes';

const { Trace } = proto;
export interface ApolloServerPluginInlineTraceOptions {
/**
* By default, all errors from this service get included in the trace. You
Expand Down
18 changes: 7 additions & 11 deletions packages/server/src/plugin/traceTreeBuilder.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
// This class is a helper for ApolloServerPluginUsageReporting and
// ApolloServerPluginInlineTrace.
import { GraphQLError, GraphQLResolveInfo, ResponsePath } from 'graphql';
import proto from '@apollo/usage-reporting-protobuf';
import { Trace, google } from '@apollo/usage-reporting-protobuf';
import type { Logger } from '@apollo/utils.logger';

const { Trace, google } = proto;

function internalError(message: string) {
return new Error(`[internal apollo-server error] ${message}`);
}
Expand All @@ -26,7 +24,7 @@ export class TraceTreeBuilder {
});
public startHrTime?: [number, number];
private stopped = false;
private nodes = new Map<string, proto.Trace.Node>([
private nodes = new Map<string, Trace.Node>([
[responsePathAsString(), this.rootNode],
]);
private readonly rewriteError?: (err: GraphQLError) => GraphQLError | null;
Expand Down Expand Up @@ -119,7 +117,7 @@ export class TraceTreeBuilder {

private addProtobufError(
path: ReadonlyArray<string | number> | undefined,
error: proto.Trace.Error,
error: Trace.Error,
) {
if (!this.startHrTime) {
throw internalError('addProtobufError called before startTiming!');
Expand Down Expand Up @@ -148,7 +146,7 @@ export class TraceTreeBuilder {
node.error.push(error);
}

private newNode(path: ResponsePath): proto.Trace.Node {
private newNode(path: ResponsePath): Trace.Node {
const node = new Trace.Node();
const id = path.key;
if (typeof id === 'number') {
Expand All @@ -162,7 +160,7 @@ export class TraceTreeBuilder {
return node;
}

private ensureParentNode(path: ResponsePath): proto.Trace.Node {
private ensureParentNode(path: ResponsePath): Trace.Node {
const parentPath = responsePathAsString(path.prev);
const parentNode = this.nodes.get(parentPath);
if (parentNode) {
Expand Down Expand Up @@ -262,7 +260,7 @@ function responsePathAsString(p?: ResponsePath): string {
return res;
}

function errorToProtobufError(error: GraphQLError): proto.Trace.Error {
function errorToProtobufError(error: GraphQLError): Trace.Error {
return new Trace.Error({
message: error.message,
location: (error.locations || []).map(
Expand All @@ -273,9 +271,7 @@ function errorToProtobufError(error: GraphQLError): proto.Trace.Error {
}

// Converts a JS Date into a Timestamp.
export function dateToProtoTimestamp(
date: Date,
): proto.google.protobuf.Timestamp {
export function dateToProtoTimestamp(date: Date): google.protobuf.Timestamp {
const totalMillis = +date;
const millis = totalMillis % 1000;
return new google.protobuf.Timestamp({
Expand Down
34 changes: 16 additions & 18 deletions packages/server/src/plugin/usageReporting/plugin.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import proto from '@apollo/usage-reporting-protobuf';
import { Report, ReportHeader, Trace } from '@apollo/usage-reporting-protobuf';
import type { Fetcher, FetcherResponse } from '@apollo/utils.fetcher';
import {
usageReportingSignature,
Expand Down Expand Up @@ -38,8 +38,6 @@ import { OurReport } from './stats.js';
import { makeTraceDetails } from './traceDetails.js';
import { packageVersion } from '../../packageVersion.js';

const { ReportHeader } = proto;

const reportHeaderDefaults = {
hostname: os.hostname(),
agentVersion: `@apollo/server@${packageVersion}`,
Expand All @@ -50,7 +48,7 @@ const reportHeaderDefaults = {

class ReportData {
report!: OurReport;
readonly header: proto.ReportHeader;
readonly header: ReportHeader;
constructor(executableSchemaId: string, graphRef: string) {
this.header = new ReportHeader({
...reportHeaderDefaults,
Expand Down Expand Up @@ -246,11 +244,11 @@ export function ApolloServerPluginUsageReporting<TContext extends BaseContext>(

report.ensureCountsAreIntegers();

const protobufError = proto.Report.verify(report);
const protobufError = Report.verify(report);
if (protobufError) {
throw new Error(`Error encoding report: ${protobufError}`);
}
const message = proto.Report.encode(report).finish();
const message = Report.encode(report).finish();

// Potential follow-up: we can compare message.length to
// report.sizeEstimator.bytes and use it to "learn" if our estimation is
Expand All @@ -269,7 +267,7 @@ export function ApolloServerPluginUsageReporting<TContext extends BaseContext>(
//
// We decode the report rather than printing the original `report`
// so that it includes all of the pre-encoded traces.
const decodedReport = proto.Report.decode(message);
const decodedReport = Report.decode(message);
logger.warn(
`Apollo usage report: ${JSON.stringify(decodedReport.toJSON())}`,
);
Expand Down Expand Up @@ -403,11 +401,11 @@ export function ApolloServerPluginUsageReporting<TContext extends BaseContext>(
let includeOperationInUsageReporting: boolean | null = null;

if (http) {
treeBuilder.trace.http = new proto.Trace.HTTP({
treeBuilder.trace.http = new Trace.HTTP({
method:
proto.Trace.HTTP.Method[
http.method as keyof typeof proto.Trace.HTTP.Method
] || proto.Trace.HTTP.Method.UNKNOWN,
Trace.HTTP.Method[
http.method as keyof typeof Trace.HTTP.Method
] || Trace.HTTP.Method.UNKNOWN,
// Host and path are not used anywhere on the backend, so let's not bother
// trying to parse request.url to get them, which is a potential
// source of bugs because integrations have different behavior here.
Expand Down Expand Up @@ -594,13 +592,13 @@ export function ApolloServerPluginUsageReporting<TContext extends BaseContext>(
const policyIfCacheable =
requestContext.overallCachePolicy.policyIfCacheable();
if (policyIfCacheable) {
treeBuilder.trace.cachePolicy = new proto.Trace.CachePolicy({
treeBuilder.trace.cachePolicy = new Trace.CachePolicy({
scope:
policyIfCacheable.scope === 'PRIVATE'
? proto.Trace.CachePolicy.Scope.PRIVATE
? Trace.CachePolicy.Scope.PRIVATE
: policyIfCacheable.scope === 'PUBLIC'
? proto.Trace.CachePolicy.Scope.PUBLIC
: proto.Trace.CachePolicy.Scope.UNKNOWN,
? Trace.CachePolicy.Scope.PUBLIC
: Trace.CachePolicy.Scope.UNKNOWN,
// Convert from seconds to ns.
maxAgeNs: policyIfCacheable.maxAge * 1e9,
});
Expand Down Expand Up @@ -671,7 +669,7 @@ export function ApolloServerPluginUsageReporting<TContext extends BaseContext>(
operationDerivedData.referencedFieldsByType;
}

const protobufError = proto.Trace.verify(trace);
const protobufError = Trace.verify(trace);
if (protobufError) {
throw new Error(`Error encoding trace: ${protobufError}`);
}
Expand Down Expand Up @@ -787,7 +785,7 @@ export function ApolloServerPluginUsageReporting<TContext extends BaseContext>(
}

export function makeHTTPRequestHeaders(
http: proto.Trace.IHTTP,
http: Trace.IHTTP,
headers: HeaderMap,
sendHeaders?: SendValuesBaseOptions,
): void {
Expand Down Expand Up @@ -823,7 +821,7 @@ export function makeHTTPRequestHeaders(
case 'set-cookie':
break;
default:
http!.requestHeaders![key] = new proto.Trace.HTTP.Values({
http!.requestHeaders![key] = new Trace.HTTP.Values({
value: [value],
});
}
Expand Down
39 changes: 17 additions & 22 deletions packages/server/src/plugin/usageReporting/stats.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
import type {
google,
IContextualizedStats,
IFieldStat,
IPathErrorStats,
IQueryLatencyStats,
IReport,
IStatsContext,
ITracesAndStats,
ITypeStat,
ReportHeader,
import {
type google,
type IContextualizedStats,
type IFieldStat,
type IPathErrorStats,
type IQueryLatencyStats,
type IReport,
type IStatsContext,
type ITracesAndStats,
type ITypeStat,
type ReportHeader,
Trace,
} from '@apollo/usage-reporting-protobuf';
import proto from '@apollo/usage-reporting-protobuf';
import type { ReferencedFieldsByType } from '@apollo/utils.usagereporting';
import { DurationHistogram } from './durationHistogram.js';
import { iterateOverTrace, ResponseNamePath } from './iterateOverTrace.js';

const { Trace } = proto;

// protobuf.js exports both a class and an interface (starting with I) for each
// message type. The class is what it produces when it decodes the message; the
// interface is what is accepted as input. We build up our messages using custom
Expand Down Expand Up @@ -66,7 +64,7 @@ export class OurReport implements Required<IReport> {
referencedFieldsByType,
}: {
statsReportKey: string;
trace: proto.Trace;
trace: Trace;
asTrace: boolean;
includeTracesContributingToStats: boolean;
referencedFieldsByType: ReferencedFieldsByType;
Expand Down Expand Up @@ -161,15 +159,15 @@ class StatsByContext {
}
}

addTrace(trace: proto.Trace, sizeEstimator: SizeEstimator) {
addTrace(trace: Trace, sizeEstimator: SizeEstimator) {
this.getContextualizedStats(trace, sizeEstimator).addTrace(
trace,
sizeEstimator,
);
}

private getContextualizedStats(
trace: proto.Trace,
trace: Trace,
sizeEstimator: SizeEstimator,
): OurContextualizedStats {
const statsContext: IStatsContext = {
Expand Down Expand Up @@ -211,7 +209,7 @@ export class OurContextualizedStats implements Required<IContextualizedStats> {
// We only add to the estimate when adding whole sub-messages. If it really
// mattered, we could do a lot more careful things like incrementing it
// whenever a numeric field on queryLatencyStats gets incremented over 0.
addTrace(trace: proto.Trace, sizeEstimator: SizeEstimator) {
addTrace(trace: Trace, sizeEstimator: SizeEstimator) {
const { fieldExecutionWeight } = trace;
if (!fieldExecutionWeight) {
this.queryLatencyStats.requestsWithoutFieldInstrumentation++;
Expand Down Expand Up @@ -262,10 +260,7 @@ export class OurContextualizedStats implements Required<IContextualizedStats> {

let hasError = false;

const traceNodeStats = (
node: proto.Trace.INode,
path: ResponseNamePath,
) => {
const traceNodeStats = (node: Trace.INode, path: ResponseNamePath) => {
// Generate error stats and error path information
if (node.error?.length) {
hasError = true;
Expand Down
6 changes: 2 additions & 4 deletions packages/server/src/plugin/usageReporting/traceDetails.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import proto from '@apollo/usage-reporting-protobuf';
import { Trace } from '@apollo/usage-reporting-protobuf';
import type { VariableValueOptions } from './options';

const { Trace } = proto;

// Creates trace details from request variables, given a specification for modifying
// values of private or sensitive variables.
// The details will include all variable names and their (possibly hidden or modified) values.
Expand All @@ -14,7 +12,7 @@ export function makeTraceDetails(
variables: Record<string, any>,
sendVariableValues?: VariableValueOptions,
operationString?: string,
): proto.Trace.Details {
): Trace.Details {
const details = new Trace.Details();
const variablesToRecord = (() => {
if (sendVariableValues && 'transform' in sendVariableValues) {
Expand Down
2 changes: 0 additions & 2 deletions packages/usage-reporting-protobuf/generated/index.d.ts

This file was deleted.

12 changes: 0 additions & 12 deletions packages/usage-reporting-protobuf/generated/index.js

This file was deleted.

Loading

0 comments on commit 64b2d63

Please sign in to comment.