Skip to content

Commit

Permalink
NEBULA-2011: add hideCookieToggle option and deprecate `includeCook…
Browse files Browse the repository at this point in the history
…ies` config option (#215)

* update embedded sandbox to deprecate old includeCookies and pass initialCookies and hideCookieToggle from initialState

cleanup embedded sandbox

cleanup

adjust sandbox config

* setup embedded explorer to match sandbox and pass through includeCookies to fetch

adjust explorer config

* make changes backwards compatible

* pass includeCookies through to introspection request

* adjust embedded explorer based on review

* update sandbox based on review

* add changeset

* Adjust EmbeddedExplorer deprecated text

Co-authored-by: mayakoneval <[email protected]>

* Update warning text for embedded explorer

Co-authored-by: mayakoneval <[email protected]>

* Update changelog text

Co-authored-by: mayakoneval <[email protected]>

* fix lint issue

---------

Co-authored-by: mayakoneval <[email protected]>
  • Loading branch information
esilverm and mayakoneval authored Feb 8, 2023
1 parent 1f60f54 commit e542db7
Show file tree
Hide file tree
Showing 9 changed files with 101 additions and 13 deletions.
6 changes: 6 additions & 0 deletions .changeset/brown-flowers-listen.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@apollo/explorer': major
'@apollo/sandbox': major
---

This major release affects how we send cookies to your embedded Sandbox and embedded Explorer. Previously, when a user passed the `includeCookies` config option we would set cookies on the default `fetch` request. However, when working in Sandbox or Explorer in Studio we let users set `includeCookies` in their connection settings. This change deprecates the old `includeCookies` option and passes the `includeCookies` value set in Explorer to your embedded Explorer or embedded Sandbox. In embedded Sandbox, you can configure whether cookies are initially on or off for your users on first load with the new config option `initialState.includeCookies`. You can decide to show or hide the connection settings toggle for your users with the config option `hideCookieToggle`. This change is backwards compatible, so if you are using the deprecated `includeCookies` config option, that overrides all other config options & your Studio settings.
17 changes: 15 additions & 2 deletions packages/explorer/src/EmbeddedExplorer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,12 @@ export interface BaseEmbeddableExplorerOptions {

// optional. defaults to `return fetch(url, fetchOptions)`
handleRequest?: HandleRequest;
// defaults to false. If you pass `handleRequest` that will override this.
/**
* If this is passed, its value will take precedence over your variant's default `includeCookies` value.
* If you pass `handleRequest`, that will override this value and its behavior.
*
* @deprecated Use the connection setting on your variant in Studio to choose whether or not to include cookies
*/
includeCookies?: boolean;
// If this object has values for `inviteToken` and `accountId`,
// any users who can see your embeddable Explorer are automatically
Expand Down Expand Up @@ -79,7 +84,9 @@ export class EmbeddedExplorer {
this.validateOptions();
this.handleRequest =
this.options.handleRequest ??
defaultHandleRequest({ includeCookies: !!this.options.includeCookies });
defaultHandleRequest({
legacyIncludeCookies: this.options.includeCookies,
});
this.uniqueEmbedInstanceId = idCounter++;
this.embeddedExplorerURL = this.getEmbeddedExplorerURL();
this.embeddedExplorerIFrameElement = this.injectEmbed();
Expand Down Expand Up @@ -156,6 +163,12 @@ export class EmbeddedExplorer {
throw new Error('"target" is required');
}

if (this.options.includeCookies !== undefined) {
console.warn(
'Passing `includeCookies` is deprecated. Remove `includeCookies` from your config, and use the setting for your variant on Studio to set whether or not to include cookies.'
);
}

if ('endpointUrl' in this.options && 'graphRef' in this.options) {
// we can't throw here for backwards compat reasons. Folks on the cdn _latest bundle
// will still be passing this
Expand Down
12 changes: 8 additions & 4 deletions packages/explorer/src/helpers/defaultHandleRequest.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import type { HandleRequest } from './postMessageRelayHelpers';

export const defaultHandleRequest = ({
includeCookies,
legacyIncludeCookies,
}: {
includeCookies: boolean;
legacyIncludeCookies?: boolean;
}): HandleRequest => {
const handleRequestWithCookiePref: HandleRequest = (endpointUrl, options) =>
fetch(endpointUrl, {
...options,
...(includeCookies
...(legacyIncludeCookies
? { credentials: 'include' }
: { credentials: 'omit' }),
: // if the user doesn't pass this value then we should use the credentials option sent from the
// studio postMessage request. otherwise this would overwrite it.
legacyIncludeCookies !== undefined
? { credentials: 'omit' }
: {}),
});
return handleRequestWithCookiePref;
};
7 changes: 7 additions & 0 deletions packages/explorer/src/helpers/postMessageRelayHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ export type IncomingEmbedMessage =
operationId: string;
variables?: Record<string, string>;
headers?: Record<string, string>;
// TODO (evan, 2023-02): We should make includeCookies non-optional in a few months to account for service workers refreshing
includeCookies?: boolean;
endpointUrl?: string;
}>
| MessageEvent<{
Expand Down Expand Up @@ -183,6 +185,7 @@ export function executeOperation({
operationName,
variables,
headers,
includeCookies,
embeddedIFrameElement,
operationId,
embedUrl,
Expand All @@ -195,6 +198,7 @@ export function executeOperation({
operationName: string | undefined;
variables?: Record<string, string>;
headers?: Record<string, string>;
includeCookies?: boolean;
embedUrl: string;
}) {
return handleRequest(endpointUrl, {
Expand All @@ -205,6 +209,9 @@ export function executeOperation({
variables,
operationName,
}),
...(!!includeCookies
? { credentials: 'include' }
: { credentials: 'omit' }),
})
.then(async (response) => {
const responseHeaders: Record<string, string> = {};
Expand Down
2 changes: 2 additions & 0 deletions packages/explorer/src/setupEmbedRelay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ export function setupEmbedRelay({
data;

if (isQueryOrMutation) {
const { includeCookies } = data;
// we support the old way of using the embed when we didn't require folks to have
// studio graphs, which is to pass in an endpoint manually. However, we use the
// endpoint sent to us from studio if there is no endpoint passed in manually
Expand All @@ -111,6 +112,7 @@ export function setupEmbedRelay({
operationName,
variables,
headers,
includeCookies,
embeddedIFrameElement: embeddedExplorerIFrameElement,
operationId,
embedUrl,
Expand Down
39 changes: 37 additions & 2 deletions packages/sandbox/src/EmbeddedSandbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,26 @@ export interface EmbeddableSandboxOptions {
document?: string;
variables?: JSONObject;
headers?: Record<string, string>;
includeCookies?: boolean; // defaults to false
};

// optional. defaults to `return fetch(url, fetchOptions)`
handleRequest?: HandleRequest;
// defaults to false. If you pass `handleRequest` that will override this.

/**
* optional. If this is passed, its value will take precedence over your sandbox connection settings `includeCookies` value.
* If you pass `handleRequest`, that will override this value and its behavior.
*
* @deprecated Use `initialState.includeCookies` instead
*/
includeCookies?: boolean;

/**
* optional. defaults to `true`.
* Set this to `false` if you want individual users to be able to choose whether
* to include cookies in their request from their connection settings.
*/
hideCookieToggle?: boolean;
}

type InternalEmbeddableSandboxOptions = EmbeddableSandboxOptions & {
Expand All @@ -41,7 +55,9 @@ export class EmbeddedSandbox {
this.validateOptions();
this.handleRequest =
this.options.handleRequest ??
defaultHandleRequest({ includeCookies: !!this.options.includeCookies });
defaultHandleRequest({
legacyIncludeCookies: this.options.includeCookies,
});
this.uniqueEmbedInstanceId = idCounter++;
this.embeddedSandboxIFrameElement = this.injectEmbed();
this.disposable = setupSandboxEmbedRelay({
Expand All @@ -68,6 +84,7 @@ export class EmbeddedSandbox {
document: initialDocument,
variables,
headers,
includeCookies,
} = this.options.initialState || {};

const queryParams = {
Expand All @@ -81,6 +98,8 @@ export class EmbeddedSandbox {
defaultHeaders: headers
? encodeURIComponent(JSON.stringify(headers))
: undefined,
defaultIncludeCookies: includeCookies,
hideCookieToggle: this.options.hideCookieToggle ?? true,
parentSupportsSubscriptions: true,
version: packageJSON.version,
runTelemetry: true,
Expand Down Expand Up @@ -141,5 +160,21 @@ export class EmbeddedSandbox {
if (!this.options.target) {
throw new Error('"target" is required');
}

if (this.options.includeCookies !== undefined) {
console.warn(
'Passing `includeCookies` is deprecated. If you would like to set a default includeCookies value, please use `initialState.includeCookies` instead.'
);
}

if (
this.options.includeCookies !== undefined &&
(this.options.hideCookieToggle !== undefined ||
this.options.initialState?.includeCookies !== undefined)
) {
throw new Error(
'Passing `includeCookies` is deprecated and will override your sandbox connection settings configuration.'
);
}
}
}
12 changes: 8 additions & 4 deletions packages/sandbox/src/helpers/defaultHandleRequest.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import type { HandleRequest } from './postMessageRelayHelpers';

export const defaultHandleRequest = ({
includeCookies,
legacyIncludeCookies,
}: {
includeCookies: boolean;
legacyIncludeCookies?: boolean;
}): HandleRequest => {
const handleRequestWithCookiePref: HandleRequest = (endpointUrl, options) =>
fetch(endpointUrl, {
...options,
...(includeCookies
...(legacyIncludeCookies
? { credentials: 'include' }
: { credentials: 'omit' }),
: // if the user doesn't pass this value then we should use the credentials option sent from the
// studio postMessage request. otherwise this would overwrite it.
legacyIncludeCookies !== undefined
? { credentials: 'omit' }
: {}),
});
return handleRequestWithCookiePref;
};
14 changes: 14 additions & 0 deletions packages/sandbox/src/helpers/postMessageRelayHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,8 @@ export type IncomingEmbedMessage =
operationId: string;
variables?: Record<string, string>;
headers?: Record<string, string>;
// TODO (evan, 2023-02): We should make includeCookies non-optional in a few months to account for service workers refreshing
includeCookies?: boolean;
endpointUrl: string;
}>
| MessageEvent<{
Expand Down Expand Up @@ -188,6 +190,8 @@ export type IncomingEmbedMessage =
name: typeof INTROSPECTION_QUERY_WITH_HEADERS;
introspectionRequestBody: string;
introspectionRequestHeaders: Record<string, string>;
// TODO (evan, 2023-02): We should make includeCookies non-optional in a few months to account for service workers refreshing
includeCookies?: boolean;
sandboxEndpointUrl?: string;
operationId: string;
}>;
Expand All @@ -199,6 +203,7 @@ export function executeOperation({
operationName,
variables,
headers,
includeCookies,
embeddedIFrameElement,
operationId,
embedUrl,
Expand All @@ -211,6 +216,7 @@ export function executeOperation({
operationName: string | undefined;
variables?: Record<string, string>;
headers?: Record<string, string>;
includeCookies?: boolean;
embedUrl: string;
}) {
return handleRequest(endpointUrl, {
Expand All @@ -221,6 +227,9 @@ export function executeOperation({
variables,
operationName,
}),
...(!!includeCookies
? { credentials: 'include' }
: { credentials: 'omit' }),
})
.then(async (response) => {
const responseHeaders: Record<string, string> = {};
Expand Down Expand Up @@ -351,6 +360,7 @@ export function executeOperation({
export function executeIntrospectionRequest({
endpointUrl,
headers,
includeCookies,
introspectionRequestBody,
embeddedIFrameElement,
embedUrl,
Expand All @@ -360,6 +370,7 @@ export function executeIntrospectionRequest({
endpointUrl: string;
embeddedIFrameElement: HTMLIFrameElement;
headers?: Record<string, string>;
includeCookies?: boolean;
introspectionRequestBody: string;
embedUrl: string;
handleRequest: HandleRequest;
Expand All @@ -376,6 +387,9 @@ export function executeIntrospectionRequest({
query,
operationName,
}),
...(!!includeCookies
? { credentials: 'include' }
: { credentials: 'omit' }),
})
.then((response) => response.json())
.then((response) => {
Expand Down
5 changes: 4 additions & 1 deletion packages/sandbox/src/setupSandboxEmbedRelay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export function setupSandboxEmbedRelay({
const {
introspectionRequestBody,
introspectionRequestHeaders,
includeCookies,
sandboxEndpointUrl,
operationId,
} = data;
Expand All @@ -63,6 +64,7 @@ export function setupSandboxEmbedRelay({
endpointUrl: sandboxEndpointUrl,
introspectionRequestBody,
headers: introspectionRequestHeaders,
includeCookies,
embeddedIFrameElement: embeddedSandboxIFrameElement,
embedUrl,
handleRequest,
Expand All @@ -86,7 +88,7 @@ export function setupSandboxEmbedRelay({
const { operation, operationId, operationName, variables, headers } =
data;
if (isQueryOrMutation) {
const { endpointUrl } = data;
const { endpointUrl, includeCookies } = data;
if (!endpointUrl) {
throw new Error(
'Something went wrong, we should not have gotten here. The sandbox endpoint url was not sent.'
Expand All @@ -99,6 +101,7 @@ export function setupSandboxEmbedRelay({
operationName,
variables,
headers,
includeCookies,
embeddedIFrameElement: embeddedSandboxIFrameElement,
operationId,
embedUrl,
Expand Down

0 comments on commit e542db7

Please sign in to comment.