Skip to content

Commit

Permalink
Allow disabling warnings for masked field access with @unmask
Browse files Browse the repository at this point in the history
  • Loading branch information
jerelmiller committed Jul 16, 2024
1 parent 470e32a commit 5d0f2ad
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 9 deletions.
64 changes: 64 additions & 0 deletions src/__tests__/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7478,6 +7478,70 @@ describe("data masking", () => {
expect(consoleSpy.warn).toHaveBeenCalledTimes(1);
}
});

it("allows disabling warnings when accessing a fragmented field while using @unmask", async () => {
using consoleSpy = spyOnConsole("warn");

interface Query {
currentUser: {
__typename: "User";
id: number;
name: string;
age: number;
};
}

const query: TypedDocumentNode<Query, never> = gql`
query UnmaskedQuery @unmask(warnOnFieldAccess: false) {
currentUser {
id
name
...UserFields
}
}
fragment UserFields on User {
age
name
}
`;

const mocks = [
{
request: { query },
result: {
data: {
currentUser: {
__typename: "User",
id: 1,
name: "Test User",
age: 34,
},
},
},
delay: 20,
},
];

const client = new ApolloClient({
dataMasking: true,
cache: new InMemoryCache(),
link: new MockLink(mocks),
});

const observable = client.watchQuery({ query });
const stream = new ObservableStream(observable);

{
const { data } = await stream.takeNext();
data.currentUser.__typename;
data.currentUser.id;
data.currentUser.name;
data.currentUser.age;

expect(consoleSpy.warn).not.toHaveBeenCalled();
}
});
});

function clientRoundtrip(
Expand Down
35 changes: 26 additions & 9 deletions src/core/masking.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,14 @@ export function maskQuery<TData = unknown>(
): TData {
const definition = getMainDefinition(document);
const fragmentMap = createFragmentMap(getFragmentDefinitions(document));
const [isUnmasked, { warnOnFieldAccess }] = isUnmaskedDocument(document);
const [masked, changed] = maskSelectionSet(
data,
definition.selectionSet,
matchesFragment,
fragmentMap,
isUnmaskedDocument(document)
isUnmasked,
warnOnFieldAccess
);

return changed ? masked : data;
Expand Down Expand Up @@ -75,7 +77,8 @@ export function maskFragment<TData = unknown>(
fragment.selectionSet,
matchesFragment,
fragmentMap,
false
false,
true
);

return changed ? masked : data;
Expand All @@ -86,7 +89,8 @@ function maskSelectionSet(
selectionSet: SelectionSetNode,
matchesFragment: MatchesFragmentFn,
fragmentMap: FragmentMap,
isUnmasked: boolean
isUnmasked: boolean,
warnOnFieldAccess: boolean
): [data: any, changed: boolean] {
if (Array.isArray(data)) {
let changed = false;
Expand All @@ -97,7 +101,8 @@ function maskSelectionSet(
selectionSet,
matchesFragment,
fragmentMap,
isUnmasked
isUnmasked,
warnOnFieldAccess
);
changed ||= itemChanged;

Expand Down Expand Up @@ -132,7 +137,8 @@ function maskSelectionSet(
childSelectionSet,
matchesFragment,
fragmentMap,
isUnmasked
isUnmasked,
warnOnFieldAccess
);

if (childChanged) {
Expand All @@ -156,7 +162,8 @@ function maskSelectionSet(
selection.selectionSet,
matchesFragment,
fragmentMap,
isUnmasked
isUnmasked,
warnOnFieldAccess
);

return [
Expand All @@ -172,7 +179,12 @@ function maskSelectionSet(

return [
isUnmasked ?
addAccessorWarnings(memo, data, fragment.selectionSet)
addAccessorWarnings(
memo,
data,
fragment.selectionSet,
warnOnFieldAccess
)
: memo,
true,
];
Expand All @@ -185,7 +197,8 @@ function maskSelectionSet(
function addAccessorWarnings(
memo: Record<string, unknown>,
parent: Record<string, unknown>,
selectionSetNode: SelectionSetNode
selectionSetNode: SelectionSetNode,
warnOnFieldAccess: boolean
) {
selectionSetNode.selections.forEach((selection) => {
switch (selection.kind) {
Expand All @@ -196,7 +209,11 @@ function addAccessorWarnings(
return;
}

return addAccessorWarning(memo, parent[keyName], keyName);
if (warnOnFieldAccess) {
return addAccessorWarning(memo, parent[keyName], keyName);
} else {
memo[keyName] = parent[keyName];
}
}
}
});
Expand Down

0 comments on commit 5d0f2ad

Please sign in to comment.