Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions package-lock.json

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

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"/oclif.manifest.json"
],
"dependencies": {
"@apollo/client": "^3.11.8",
"@apollo/client": "^3.14.0",
"@contentstack/cli-command": "^1.4.0",
"@contentstack/cli-utilities": "^1.12.0",
"@oclif/core": "^4.2.7",
Expand Down
38 changes: 38 additions & 0 deletions src/util/apollo-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,50 @@ import {
Operation,
ApolloClient,
InMemoryCache,
setLogVerbosity,
} from '@apollo/client/core';
import { cliux as ux, authHandler, configHandler } from '@contentstack/cli-utilities';

import config from '../config';
import { GraphqlApiClientInput } from '../types';

export const isNotDevelopment = process.env.NODE_ENV !== 'development';

function isApolloMessage(message: string): boolean {
return (
message.includes('go.apollo.dev/c/err') ||
message.includes('cache.diff') ||
message.includes('canonizeResults')
);
}

if (isNotDevelopment) {
try {
setLogVerbosity('silent');
} catch {}

const originalError = console.error;
const originalWarn = console.warn;

console.error = (...args: any[]) => {
const message = args[0]?.toString() || '';

if (isApolloMessage(message)) {
return;
}
originalError.apply(console, args);
};

console.warn = (...args: any[]) => {
const message = args[0]?.toString() || '';

if (isApolloMessage(message)) {
return;
}
originalWarn.apply(console, args);
};
}

export default class GraphqlApiClient {
private authType: string;
private cmaHost: string | undefined;
Expand Down
71 changes: 67 additions & 4 deletions src/util/logs-polling-utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Ora } from 'ora';
import { LogPollingInput, ConfigType } from '../types';
import { deploymentQuery, deploymentLogsQuery, serverlessLogsQuery } from '../graphql';
import { setTimeout as sleep } from 'timers/promises';
import { isNotDevelopment } from './apollo-client';

export default class LogPolling {
private config: ConfigType;
Expand All @@ -25,6 +26,61 @@ export default class LogPolling {
if ($event) this.$event = $event;
}

/**
* @method withDeprecationsDisabled - Helper to disable Apollo Client deprecation warnings
*
* Wraps the provided function so that Apollo deprecation warnings are disabled
* only during its execution, and restored immediately after.
*/
private withDeprecationsDisabled<T>(fn: () => T): T {

if (!isNotDevelopment) {
return fn();
}

let withDisabledDeprecations: any;
try {
withDisabledDeprecations = require('@apollo/client/utilities/deprecation').withDisabledDeprecations;
} catch {
return fn();
}

const handler = withDisabledDeprecations();
try {
return fn();
} finally {
this.disposeDeprecationHandler(handler);
}
}

private disposeDeprecationHandler(handler?: any): void {
if (!handler) return;
try {
const dispose = (handler as any)[(Symbol as any).dispose];
if (typeof dispose === 'function') {
dispose.call(handler);
return;
}
} catch {}
try {
const asyncDispose = (handler as any)[(Symbol as any).asyncDispose];
if (typeof asyncDispose === 'function') {
asyncDispose.call(handler);
return;
}
} catch {}
try {
const symbols = Object.getOwnPropertySymbols(handler);
for (const sym of symbols) {
const maybeDispose = (handler as any)[sym];
if (typeof maybeDispose === 'function') {
maybeDispose.call(handler);
break;
}
}
} catch {}
}

/**
* @method getDeploymentStatus - deployment status polling
*
Expand All @@ -43,7 +99,8 @@ export default class LogPolling {
};
}
> {
const statusWatchQuery = this.apolloManageClient.watchQuery({
return this.withDeprecationsDisabled(() => {
const statusWatchQuery = this.apolloManageClient.watchQuery({
fetchPolicy: 'network-only',
query: deploymentQuery,
variables: {
Expand All @@ -55,7 +112,8 @@ export default class LogPolling {
pollInterval: this.config.pollingInterval,
errorPolicy: 'all',
});
return statusWatchQuery;
return statusWatchQuery;
});
}

/**
Expand Down Expand Up @@ -86,7 +144,8 @@ export default class LogPolling {
statusWatchQuery.stopPolling();
}
});
const logsWatchQuery = this.apolloLogsClient.watchQuery({
const logsWatchQuery = this.withDeprecationsDisabled(() => {
return this.apolloLogsClient.watchQuery({
fetchPolicy: 'network-only',
query: deploymentLogsQuery,
variables: {
Expand All @@ -95,6 +154,7 @@ export default class LogPolling {
pollInterval: this.config.pollingInterval,
errorPolicy: 'all',
});
});
this.subscribeDeploymentLogs(logsWatchQuery);
}

Expand Down Expand Up @@ -180,7 +240,9 @@ export default class LogPolling {
async serverLogs(): Promise<void> {
this.startTime = new Date().getTime() - 10 * 1000;
this.endTime = new Date().getTime();
const serverLogsWatchQuery = this.apolloLogsClient.watchQuery({

const serverLogsWatchQuery = this.withDeprecationsDisabled(() => {
return this.apolloLogsClient.watchQuery({
fetchPolicy: 'network-only',
query: serverlessLogsQuery,
variables: {
Expand All @@ -194,6 +256,7 @@ export default class LogPolling {
pollInterval: this.config.pollingInterval,
errorPolicy: 'all',
});
});
this.subscribeServerLogs(serverLogsWatchQuery);
}

Expand Down
121 changes: 121 additions & 0 deletions test/unit/util/apollo-client.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
//@ts-nocheck
import { describe, it, beforeEach, afterEach } from 'mocha';
import { expect } from 'chai';
import { createSandbox } from 'sinon';

describe('Apollo Client Console Suppression', () => {
let sandbox;
let originalEnv;
let originalError;
let originalWarn;
let modulePath;

beforeEach(() => {
sandbox = createSandbox();
originalEnv = process.env.NODE_ENV;
originalError = console.error;
originalWarn = console.warn;
modulePath = require.resolve('../../../src/util/apollo-client');
});

afterEach(() => {
process.env.NODE_ENV = originalEnv;
console.error = originalError;
console.warn = originalWarn;
sandbox.restore();

if (require.cache[modulePath]) {
delete require.cache[modulePath];
}
});

it('should show errors/warnings when NODE_ENV is development', () => {
process.env.NODE_ENV = 'development';

const errorSpy = sandbox.spy();
const warnSpy = sandbox.spy();

delete require.cache[modulePath];

console.error = errorSpy;
console.warn = warnSpy;

const apolloClientModule = require('../../../src/util/apollo-client');

expect(apolloClientModule.isNotDevelopment).to.be.false;

const apolloErrorMsg = 'Error: go.apollo.dev/c/err/test';
const apolloWarnMsg = 'Warning: cache.diff issue';
const regularErrorMsg = 'Regular error message';
const regularWarnMsg = 'Regular warning message';

console.error(apolloErrorMsg);
console.warn(apolloWarnMsg);
console.error(regularErrorMsg);
console.warn(regularWarnMsg);

expect(errorSpy.callCount).to.equal(2);
expect(warnSpy.callCount).to.equal(2);
expect(errorSpy.calledWith(apolloErrorMsg)).to.be.true;
expect(errorSpy.calledWith(regularErrorMsg)).to.be.true;
expect(warnSpy.calledWith(apolloWarnMsg)).to.be.true;
expect(warnSpy.calledWith(regularWarnMsg)).to.be.true;
});

it('should suppress Apollo errors/warnings when NODE_ENV is not development', () => {
process.env.NODE_ENV = 'isNotDevelopment';

const originalErrorBefore = console.error;
const originalWarnBefore = console.warn;

const errorSpy = sandbox.spy(originalErrorBefore);
const warnSpy = sandbox.spy(originalWarnBefore);

console.error = errorSpy;
console.warn = warnSpy;

delete require.cache[modulePath];

const apolloClientModule = require('../../../src/util/apollo-client');

expect(apolloClientModule.isNotDevelopment).to.be.true;
expect(console.error).to.not.equal(errorSpy);
expect(console.warn).to.not.equal(warnSpy);

const apolloErrorMsg = 'Error: go.apollo.dev/c/err/test';
const apolloWarnMsg = 'Warning: cache.diff issue';
const apolloCanonizeMsg = 'Warning: canonizeResults deprecated';
const regularErrorMsg = 'Regular error message';
const regularWarnMsg = 'Regular warning message';

console.error(apolloErrorMsg);
console.warn(apolloWarnMsg);
console.warn(apolloCanonizeMsg);
console.error(regularErrorMsg);
console.warn(regularWarnMsg);

const errorCalls = errorSpy.getCalls();
const warnCalls = warnSpy.getCalls();

const regularErrorLogged = errorCalls.some((call) =>
call.args[0] === regularErrorMsg || call.args[0]?.toString() === regularErrorMsg
);
const regularWarnLogged = warnCalls.some((call) =>
call.args[0] === regularWarnMsg || call.args[0]?.toString() === regularWarnMsg
);

expect(regularErrorLogged).to.be.true;
expect(regularWarnLogged).to.be.true;

const apolloErrorLogged = errorCalls.some((call) =>
call.args[0]?.toString().includes('go.apollo.dev/c/err')
);
const apolloWarnLogged = warnCalls.some((call) =>
call.args[0]?.toString().includes('cache.diff') ||
call.args[0]?.toString().includes('canonizeResults')
);

expect(apolloErrorLogged).to.be.false;
expect(apolloWarnLogged).to.be.false;
});
});