diff --git a/plugins/graphiql/.eslintrc.js b/plugins/graphiql/.eslintrc.js
new file mode 100644
index 0000000000..6a513fbafe
--- /dev/null
+++ b/plugins/graphiql/.eslintrc.js
@@ -0,0 +1,7 @@
+module.exports = {
+ extends: [require.resolve('@backstage/cli/config/eslint')],
+ rules: {
+ // Prefer to use rendered.getBy*, which will throw an error
+ 'jest/expect-expect': 0,
+ },
+};
diff --git a/plugins/graphiql/README.md b/plugins/graphiql/README.md
new file mode 100644
index 0000000000..d2f8cafbfb
--- /dev/null
+++ b/plugins/graphiql/README.md
@@ -0,0 +1,64 @@
+# @backstage/plugin-graphiql
+
+This plugin integrates [GraphiQL](https://github.com/graphql/graphiql) as a tool to browse GraphiQL endpoints inside Backstage.
+
+The purpose of the plugin is to provide a convenient way for developers to try out GraphQL queries in their own environment.
+By exposing GraphiQL as a plugin instead of a standalone app, it's possible to provide a preconfigured environment for engineers, and also tie into authentication providers already inside Backstage.
+
+## Getting Started
+
+### Installing the plugin
+
+Start out by installing the plugin in your Backstage app:
+
+```bash
+yarn add @backstage/plugin-graphiql
+```
+
+Then add an entry to your App's `plugins.ts` to import the plugin.
+
+The plugin registers a `/graphiql` route, which you can link to from the Sidebar if desired.
+
+### Adding GraphQL endpoints
+
+For the plugin to function, you need to supply GraphQL endpoints through the GraphQLBrowse API, which is done by implementing the `GraphQLBrowseApi` exported by this plugin.
+
+If all you need is a static list of endpoints, the plugin exports a `GraphQLEndpoints` class that implements the `GraphQLBrowseApi` for you. Here's and example of how you could expose two GraphQL endpoints in your App:
+
+```tsx
+import {
+ graphQlBrowseApiRef,
+ GraphQLEndpoints,
+} from '@backstage/plugin-graphiql';
+
+// Implement the Graph QL browse API using a static list of endpoints
+const graphQlBrowseApi = GraphQLEndpoints.from([
+ // Use the .create function if all you need is a static URL and headers.
+ GraphQLEndpoints.create({
+ id: 'gitlab',
+ title: 'GitLab',
+ url: 'https://gitlab.com/api/graphql',
+ // Optional extra headers
+ headers: { Extra: 'Header' },
+ }),
+ {
+ id: 'hooli-search',
+ title: 'Hooli Search',
+ // Custom fetch function, this one is equivalent to using GraphQLEndpoints.create()
+ // with url set to https://internal.hooli.com/search
+ fetcher: async (params: any) => {
+ return fetch('https://internal.hooli.com/search', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(params),
+ }).then(res => res.json());
+ },
+ },
+]);
+
+// ApiRegistry builder created somewhere in your App
+const builder = ApiRegistry.builder();
+
+// Add the instance to the API registry
+builder.add(graphQlBrowseApiRef, graphQlBrowseApi);
+```
diff --git a/plugins/graphiql/dev/index.tsx b/plugins/graphiql/dev/index.tsx
new file mode 100644
index 0000000000..ed987c1c6a
--- /dev/null
+++ b/plugins/graphiql/dev/index.tsx
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import React, { FC } from 'react';
+import ReactDOM from 'react-dom';
+import { BrowserRouter } from 'react-router-dom';
+import HomeIcon from '@material-ui/icons/Home';
+import { ThemeProvider, CssBaseline } from '@material-ui/core';
+import {
+ createApp,
+ SidebarPage,
+ Sidebar,
+ SidebarItem,
+ SidebarSpacer,
+ ApiRegistry,
+} from '@backstage/core';
+import { lightTheme } from '@backstage/theme';
+import { plugin, GraphQLEndpoints, graphQlBrowseApiRef } from '../src';
+
+const graphQlBrowseApi = GraphQLEndpoints.from([
+ GraphQLEndpoints.create({
+ id: 'gitlab',
+ title: 'GitLab',
+ url: 'https://gitlab.com/api/graphql',
+ }),
+ GraphQLEndpoints.create({
+ id: 'countries',
+ title: 'Countries',
+ url: 'https://countries.trevorblades.com/',
+ }),
+]);
+
+const app = createApp();
+app.registerApis(ApiRegistry.from([[graphQlBrowseApiRef, graphQlBrowseApi]]));
+app.registerPlugin(plugin);
+const AppComponent = app.build();
+
+const App: FC<{}> = () => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+ReactDOM.render(, document.getElementById('root'));
diff --git a/plugins/graphiql/package.json b/plugins/graphiql/package.json
new file mode 100644
index 0000000000..f2cf8b7930
--- /dev/null
+++ b/plugins/graphiql/package.json
@@ -0,0 +1,55 @@
+{
+ "name": "@backstage/plugin-graphiql",
+ "description": "Backstage plugin for browsing GraphQL APIs",
+ "version": "0.1.1-alpha.4",
+ "private": false,
+ "publishConfig": {
+ "access": "public"
+ },
+ "homepage": "https://github.com/spotify/backstage/tree/master/plugins/graphiql#readme",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/spotify/backstage",
+ "directory": "plugins/graphiql"
+ },
+ "keywords": [
+ "backstage"
+ ],
+ "license": "Apache-2.0",
+ "main": "dist/index.cjs.js",
+ "types": "dist/index.d.ts",
+ "scripts": {
+ "build": "backstage-cli plugin:build",
+ "start": "backstage-cli plugin:serve",
+ "lint": "backstage-cli lint",
+ "test": "backstage-cli test",
+ "clean": "backstage-cli clean"
+ },
+ "devDependencies": {
+ "@backstage/cli": "^0.1.1-alpha.4",
+ "@testing-library/jest-dom": "^4.2.4",
+ "@testing-library/react": "^9.3.2",
+ "@testing-library/user-event": "^7.1.2",
+ "@types/jest": "^24.0.0",
+ "@types/node": "^12.0.0",
+ "@types/testing-library__jest-dom": "5.0.2",
+ "jest-fetch-mock": "^3.0.3",
+ "react-router-dom": "^5.1.2"
+ },
+ "dependencies": {
+ "@backstage/core": "^0.1.1-alpha.4",
+ "@backstage/test-utils": "^0.1.1-alpha.4",
+ "@backstage/theme": "^0.1.1-alpha.4",
+ "@material-ui/core": "^4.9.1",
+ "@material-ui/icons": "^4.9.1",
+ "@material-ui/lab": "4.0.0-alpha.45",
+ "graphiql": "^1.0.0-alpha.8",
+ "graphql": "15.0.0",
+ "react": "16.13.1",
+ "react-dom": "16.13.1",
+ "react-use": "^13.0.0"
+ },
+ "files": [
+ "dist"
+ ]
+}
diff --git a/plugins/graphiql/src/components/GraphiQLBrowser/GraphiQLBrowser.test.tsx b/plugins/graphiql/src/components/GraphiQLBrowser/GraphiQLBrowser.test.tsx
new file mode 100644
index 0000000000..1726c188c0
--- /dev/null
+++ b/plugins/graphiql/src/components/GraphiQLBrowser/GraphiQLBrowser.test.tsx
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import React from 'react';
+import { render } from '@testing-library/react';
+import { GraphiQLBrowser } from './GraphiQLBrowser';
+import { ThemeProvider } from '@material-ui/core';
+import { lightTheme } from '@backstage/theme';
+
+jest.mock('graphiql', () => () => '');
+
+describe('GraphiQLBrowser', () => {
+ it('should render error text if there are no endpoints', () => {
+ const rendered = render(
+
+
+ ,
+ );
+ rendered.getByText('No endpoints available');
+ });
+
+ it('should render endpoint tabs', () => {
+ const rendered = render(
+
+
+ ,
+ );
+ rendered.getByText('Endpoint A');
+ rendered.getByText('Endpoint B');
+ });
+});
diff --git a/plugins/graphiql/src/components/GraphiQLBrowser/GraphiQLBrowser.tsx b/plugins/graphiql/src/components/GraphiQLBrowser/GraphiQLBrowser.tsx
new file mode 100644
index 0000000000..e914fd9649
--- /dev/null
+++ b/plugins/graphiql/src/components/GraphiQLBrowser/GraphiQLBrowser.tsx
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import React, { FC, useState } from 'react';
+import { Tabs, Tab, makeStyles, Typography, Divider } from '@material-ui/core';
+import 'graphiql/graphiql.css';
+import GraphiQL from 'graphiql';
+import { StorageBucket } from 'lib/storage';
+import { GraphQLEndpoint } from 'lib/api';
+import { BackstageTheme } from '@backstage/theme';
+
+const useStyles = makeStyles(theme => ({
+ root: {
+ height: '100%',
+ display: 'flex',
+ flexFlow: 'column nowrap',
+ },
+ tabs: {
+ background: theme.palette.background.paper,
+ },
+ graphiQlWrapper: {
+ flex: 1,
+ '@global': {
+ '.graphiql-container': {
+ boxSizing: 'initial',
+ },
+ },
+ },
+}));
+
+type GraphiQLBrowserProps = {
+ endpoints: GraphQLEndpoint[];
+};
+
+export const GraphiQLBrowser: FC = ({ endpoints }) => {
+ const classes = useStyles();
+ const [tabIndex, setTabIndex] = useState(0);
+
+ if (!endpoints.length) {
+ return No endpoints available;
+ }
+
+ const { id, fetcher } = endpoints[tabIndex];
+ const storage = StorageBucket.forLocalStorage(`plugin/graphiql/data/${id}`);
+
+ return (
+
+
setTabIndex(value)}
+ indicatorColor="primary"
+ >
+ {endpoints.map(({ title }, index) => (
+
+ ))}
+
+
+
+
+
+
+ );
+};
diff --git a/plugins/graphiql/src/components/GraphiQLBrowser/index.ts b/plugins/graphiql/src/components/GraphiQLBrowser/index.ts
new file mode 100644
index 0000000000..cb9a4a932f
--- /dev/null
+++ b/plugins/graphiql/src/components/GraphiQLBrowser/index.ts
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export * from './GraphiQLBrowser';
diff --git a/plugins/graphiql/src/components/GraphiQLPage/GraphiQLPage.test.tsx b/plugins/graphiql/src/components/GraphiQLPage/GraphiQLPage.test.tsx
new file mode 100644
index 0000000000..d19e05524e
--- /dev/null
+++ b/plugins/graphiql/src/components/GraphiQLPage/GraphiQLPage.test.tsx
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import React from 'react';
+import { GraphiQLPage } from './GraphiQLPage';
+import { ThemeProvider } from '@material-ui/core';
+import { lightTheme } from '@backstage/theme';
+import { ApiProvider, ApiRegistry } from '@backstage/core';
+import { renderWithEffects } from '@backstage/test-utils';
+import { GraphQLBrowseApi, graphQlBrowseApiRef } from 'lib/api';
+
+jest.mock('components/GraphiQLBrowser', () => ({
+ GraphiQLBrowser: () => '',
+}));
+
+describe('GraphiQLPage', () => {
+ it('should show progress', async () => {
+ const loadingApi: GraphQLBrowseApi = {
+ async getEndpoints() {
+ await new Promise(() => {});
+ return [];
+ },
+ };
+
+ const rendered = await renderWithEffects(
+
+
+
+
+ ,
+ ,
+ );
+
+ rendered.getByText('GraphiQL');
+ rendered.getByTestId('progress');
+ });
+
+ it('should show error', async () => {
+ const loadingApi: GraphQLBrowseApi = {
+ async getEndpoints() {
+ throw new Error('NOPE');
+ },
+ };
+
+ const rendered = await renderWithEffects(
+
+
+
+
+ ,
+ );
+
+ rendered.getByText('GraphiQL');
+ rendered.getByText('Failed to load GraphQL endpoints, Error: NOPE');
+ });
+
+ it('should show GraphiQLBrowser', async () => {
+ const loadingApi: GraphQLBrowseApi = {
+ async getEndpoints() {
+ return [];
+ },
+ };
+
+ const rendered = await renderWithEffects(
+
+
+
+
+ ,
+ );
+
+ rendered.getByText('GraphiQL');
+ rendered.getByText('');
+ });
+});
diff --git a/plugins/graphiql/src/components/GraphiQLPage/GraphiQLPage.tsx b/plugins/graphiql/src/components/GraphiQLPage/GraphiQLPage.tsx
new file mode 100644
index 0000000000..39ee015bed
--- /dev/null
+++ b/plugins/graphiql/src/components/GraphiQLPage/GraphiQLPage.tsx
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import React, { FC } from 'react';
+import {
+ Content,
+ Header,
+ HeaderLabel,
+ Page,
+ Progress,
+ pageTheme,
+ useApi,
+} from '@backstage/core';
+import { useAsync } from 'react-use';
+import 'graphiql/graphiql.css';
+import { graphQlBrowseApiRef } from 'lib/api';
+import { GraphiQLBrowser } from 'components';
+import { Typography } from '@material-ui/core';
+
+export const GraphiQLPage: FC<{}> = () => {
+ const graphQlBrowseApi = useApi(graphQlBrowseApiRef);
+ const endpoints = useAsync(() => graphQlBrowseApi.getEndpoints());
+
+ let content: JSX.Element;
+
+ if (endpoints.loading) {
+ content = (
+
+
+
+ );
+ } else if (endpoints.error) {
+ content = (
+
+
+ {/* TODO: provide a proper error component */}
+ Failed to load GraphQL endpoints, {String(endpoints.error)}
+
+
+ );
+ } else {
+ content = (
+
+
+
+ );
+ }
+
+ return (
+
+
+ {content}
+
+ );
+};
diff --git a/plugins/graphiql/src/components/GraphiQLPage/index.ts b/plugins/graphiql/src/components/GraphiQLPage/index.ts
new file mode 100644
index 0000000000..ed11f03c40
--- /dev/null
+++ b/plugins/graphiql/src/components/GraphiQLPage/index.ts
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export * from './GraphiQLPage';
diff --git a/plugins/graphiql/src/components/index.ts b/plugins/graphiql/src/components/index.ts
new file mode 100644
index 0000000000..c0d2228951
--- /dev/null
+++ b/plugins/graphiql/src/components/index.ts
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export * from './GraphiQLPage';
+export * from './GraphiQLBrowser';
diff --git a/plugins/graphiql/src/index.ts b/plugins/graphiql/src/index.ts
new file mode 100644
index 0000000000..a1f5587fe1
--- /dev/null
+++ b/plugins/graphiql/src/index.ts
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export { plugin } from './plugin';
+export * from './lib/api';
diff --git a/plugins/graphiql/src/lib/api/GraphQLEndpoints.ts b/plugins/graphiql/src/lib/api/GraphQLEndpoints.ts
new file mode 100644
index 0000000000..c407d92289
--- /dev/null
+++ b/plugins/graphiql/src/lib/api/GraphQLEndpoints.ts
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { GraphQLBrowseApi, GraphQLEndpoint } from './types';
+
+// Helper for generic http endpoints
+export type EndpointConfig = {
+ id: string;
+ title: string;
+ // Endpoint URL
+ url: string;
+ // only supports POST right now
+ method?: 'POST';
+ // Defaults to setting Content-Type to application/json
+ headers?: { [name in string]: string };
+};
+
+export class GraphQLEndpoints implements GraphQLBrowseApi {
+ // Create a support
+ static create(config: EndpointConfig): GraphQLEndpoint {
+ const { id, title, url, method = 'POST' } = config;
+ return {
+ id,
+ title,
+ fetcher: async (params: any) => {
+ const body = JSON.stringify(params);
+ const headers = {
+ 'Content-Type': 'application/json',
+ ...config.headers,
+ };
+ const res = await fetch(url, {
+ method,
+ headers,
+ body,
+ });
+ return res.json();
+ },
+ };
+ }
+
+ static from(endpoints: GraphQLEndpoint[]) {
+ return new GraphQLEndpoints(endpoints);
+ }
+
+ private constructor(private readonly endpoints: GraphQLEndpoint[]) {}
+
+ async getEndpoints() {
+ return this.endpoints;
+ }
+}
diff --git a/plugins/graphiql/src/lib/api/index.ts b/plugins/graphiql/src/lib/api/index.ts
new file mode 100644
index 0000000000..bcc7966cbe
--- /dev/null
+++ b/plugins/graphiql/src/lib/api/index.ts
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export * from './GraphQLEndpoints';
+export * from './types';
diff --git a/plugins/graphiql/src/lib/api/types.ts b/plugins/graphiql/src/lib/api/types.ts
new file mode 100644
index 0000000000..6c41e2aaa0
--- /dev/null
+++ b/plugins/graphiql/src/lib/api/types.ts
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { ApiRef } from '@backstage/core';
+
+export type GraphQLEndpoint = {
+ // Will be used as unique key for storing history and query data
+ id: string;
+
+ // Displayed to the user to identify the source.
+ title: string;
+
+ // Method used send a GraphQL query.
+ // The body parameter is equivalent to the POST body to be JSON-serialized, and the
+ // return value should be the equivalent of a parsed JSON response from that POST.
+ fetcher: (body: any) => Promise;
+};
+
+export type GraphQLBrowseApi = {
+ getEndpoints(): Promise;
+};
+
+export const graphQlBrowseApiRef = new ApiRef({
+ id: 'plugin.graphiql.browse',
+ description: 'Used to supply GraphQL endpoints for browsing',
+});
diff --git a/plugins/graphiql/src/lib/storage/StorageBucket.test.ts b/plugins/graphiql/src/lib/storage/StorageBucket.test.ts
new file mode 100644
index 0000000000..d18d038cb5
--- /dev/null
+++ b/plugins/graphiql/src/lib/storage/StorageBucket.test.ts
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { StorageBucket } from './StorageBucket';
+
+describe('StorageBucket', () => {
+ it('should forbid access to unknown keys', () => {
+ const bucket = StorageBucket.forStorage(localStorage, 'hello');
+
+ expect(() => {
+ bucket['dunno-this-one'] = 'nope';
+ }).toThrow('Direct property access is not allowed for StorageBuckets');
+ expect(() => {
+ return bucket['dunno-this-one'];
+ }).toThrow('Direct property access is not allowed for StorageBuckets');
+ });
+
+ it('should not implement all methods', () => {
+ const bucket = StorageBucket.forLocalStorage('hello');
+
+ expect(() => bucket.length).toThrow('Method not implemented.');
+ expect(() => bucket.key()).toThrow('Method not implemented.');
+ });
+
+ describe('with mocked underlying storage', () => {
+ const mockStorage = {
+ getItem: jest.fn(),
+ setItem: jest.fn(),
+ removeItem: jest.fn(),
+ };
+ const bucket = StorageBucket.forStorage(
+ (mockStorage as unknown) as Storage,
+ 'my-bucket',
+ );
+
+ afterEach(() => {
+ jest.resetAllMocks();
+ });
+
+ it('should set a first item', () => {
+ bucket.setItem('x', 'a');
+
+ expect(mockStorage.getItem).toHaveBeenCalledTimes(1);
+ expect(mockStorage.getItem).toHaveBeenLastCalledWith('my-bucket');
+ expect(mockStorage.setItem).toHaveBeenCalledTimes(1);
+ expect(mockStorage.setItem).toHaveBeenLastCalledWith(
+ 'my-bucket',
+ JSON.stringify({ x: 'a' }),
+ );
+ expect(mockStorage.removeItem).toHaveBeenCalledTimes(0);
+ });
+
+ it('should set a second item', () => {
+ mockStorage.getItem.mockReturnValueOnce(JSON.stringify({ y: 'b' }));
+ bucket.setItem('x', 'a');
+
+ expect(mockStorage.getItem).toHaveBeenCalledTimes(1);
+ expect(mockStorage.getItem).toHaveBeenLastCalledWith('my-bucket');
+ expect(mockStorage.setItem).toHaveBeenCalledTimes(1);
+ expect(mockStorage.setItem).toHaveBeenLastCalledWith(
+ 'my-bucket',
+ JSON.stringify({ y: 'b', x: 'a' }),
+ );
+ expect(mockStorage.removeItem).toHaveBeenCalledTimes(0);
+ });
+
+ it('should clear the bucket', () => {
+ bucket.clear();
+
+ expect(mockStorage.getItem).toHaveBeenCalledTimes(0);
+ expect(mockStorage.setItem).toHaveBeenCalledTimes(0);
+ expect(mockStorage.removeItem).toHaveBeenCalledTimes(1);
+ expect(mockStorage.removeItem).toHaveBeenLastCalledWith('my-bucket');
+ });
+
+ it('should get an item', () => {
+ mockStorage.getItem.mockReturnValueOnce(JSON.stringify({ x: 'X' }));
+ expect(bucket.getItem('x')).toBe('X');
+
+ expect(mockStorage.getItem).toHaveBeenCalledTimes(1);
+ expect(mockStorage.getItem).toHaveBeenLastCalledWith('my-bucket');
+ expect(mockStorage.setItem).toHaveBeenCalledTimes(0);
+ expect(mockStorage.removeItem).toHaveBeenCalledTimes(0);
+ });
+
+ it('should remove an item', () => {
+ mockStorage.getItem.mockReturnValueOnce(
+ JSON.stringify({ x: 'X', y: 'Y' }),
+ );
+ bucket.removeItem('x');
+
+ expect(mockStorage.getItem).toHaveBeenCalledTimes(1);
+ expect(mockStorage.getItem).toHaveBeenLastCalledWith('my-bucket');
+ expect(mockStorage.setItem).toHaveBeenCalledTimes(1);
+ expect(mockStorage.setItem).toHaveBeenLastCalledWith(
+ 'my-bucket',
+ JSON.stringify({ y: 'Y' }),
+ );
+ expect(mockStorage.removeItem).toHaveBeenCalledTimes(0);
+ });
+
+ it('should not bother to write when deleting a missing key', () => {
+ mockStorage.getItem.mockReturnValueOnce(JSON.stringify({ y: 'Y' }));
+ bucket.removeItem('x');
+
+ expect(mockStorage.getItem).toHaveBeenCalledTimes(1);
+ expect(mockStorage.getItem).toHaveBeenLastCalledWith('my-bucket');
+ expect(mockStorage.setItem).toHaveBeenCalledTimes(0);
+ expect(mockStorage.removeItem).toHaveBeenCalledTimes(0);
+ });
+
+ it('should ignore bad data', () => {
+ mockStorage.getItem.mockReturnValue('derp');
+
+ expect(bucket.getItem('x')).toBe(null);
+
+ expect(mockStorage.getItem).toHaveBeenCalledTimes(1);
+ expect(mockStorage.getItem).toHaveBeenLastCalledWith('my-bucket');
+ expect(mockStorage.setItem).toHaveBeenCalledTimes(0);
+ expect(mockStorage.removeItem).toHaveBeenCalledTimes(0);
+
+ bucket.removeItem('x');
+
+ expect(mockStorage.getItem).toHaveBeenCalledTimes(2);
+ expect(mockStorage.getItem).toHaveBeenLastCalledWith('my-bucket');
+ expect(mockStorage.setItem).toHaveBeenCalledTimes(0);
+ expect(mockStorage.removeItem).toHaveBeenCalledTimes(0);
+ });
+ });
+});
diff --git a/plugins/graphiql/src/lib/storage/StorageBucket.ts b/plugins/graphiql/src/lib/storage/StorageBucket.ts
new file mode 100644
index 0000000000..9d275e5f0d
--- /dev/null
+++ b/plugins/graphiql/src/lib/storage/StorageBucket.ts
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+type BucketData = { [key in string]: string };
+
+export class StorageBucket implements Storage {
+ private static noPropAccessProxyHandler: ProxyHandler = {
+ get(target, prop) {
+ if (prop in target) {
+ return target[prop as any];
+ }
+ throw new Error(
+ 'Direct property access is not allowed for StorageBuckets',
+ );
+ },
+ set() {
+ throw new Error(
+ 'Direct property access is not allowed for StorageBuckets',
+ );
+ },
+ };
+
+ static forStorage(storage: Storage, bucket: string) {
+ const storageBucket = new StorageBucket(storage, bucket);
+ return new Proxy(storageBucket, StorageBucket.noPropAccessProxyHandler);
+ }
+
+ static forLocalStorage(bucket: string): StorageBucket {
+ return StorageBucket.forStorage(localStorage, bucket);
+ }
+
+ private constructor(
+ private readonly storage: Storage,
+ private readonly bucket: string,
+ ) {}
+
+ [name: string]: any;
+
+ get length(): number {
+ throw new Error('Method not implemented.');
+ }
+
+ clear(): void {
+ this.storage.removeItem(this.bucket);
+ }
+
+ getItem(key: string): string | null {
+ return this.read()?.[key] ?? null;
+ }
+
+ key(): never {
+ throw new Error('Method not implemented.');
+ }
+
+ removeItem(key: string): void {
+ const data = this.read();
+ if (!data) {
+ return;
+ }
+
+ if (key in data) {
+ delete data[key];
+ this.write(data);
+ }
+ }
+
+ setItem(key: string, value: string): void {
+ const data = this.read() ?? {};
+ data[key] = value;
+ this.write(data);
+ }
+
+ private read(): BucketData | undefined {
+ const bucketValue = this.storage.getItem(this.bucket);
+ if (!bucketValue) {
+ return undefined;
+ }
+
+ try {
+ return JSON.parse(bucketValue);
+ } catch {
+ return undefined;
+ }
+ }
+
+ private write(data: BucketData) {
+ this.storage.setItem(this.bucket, JSON.stringify(data));
+ }
+}
diff --git a/plugins/graphiql/src/lib/storage/index.ts b/plugins/graphiql/src/lib/storage/index.ts
new file mode 100644
index 0000000000..a760761e44
--- /dev/null
+++ b/plugins/graphiql/src/lib/storage/index.ts
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export * from './StorageBucket';
diff --git a/plugins/graphiql/src/plugin.test.ts b/plugins/graphiql/src/plugin.test.ts
new file mode 100644
index 0000000000..0841d3e071
--- /dev/null
+++ b/plugins/graphiql/src/plugin.test.ts
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { plugin } from './plugin';
+
+describe('graphiql', () => {
+ it('should export plugin', () => {
+ expect(plugin).toBeDefined();
+ });
+});
diff --git a/plugins/graphiql/src/plugin.ts b/plugins/graphiql/src/plugin.ts
new file mode 100644
index 0000000000..6436380c27
--- /dev/null
+++ b/plugins/graphiql/src/plugin.ts
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { createPlugin } from '@backstage/core';
+import { GraphiQLPage } from './components';
+
+export const plugin = createPlugin({
+ id: 'graphiql',
+ register({ router }) {
+ router.registerRoute('/graphiql', GraphiQLPage);
+ },
+});
diff --git a/plugins/graphiql/src/setupTests.ts b/plugins/graphiql/src/setupTests.ts
new file mode 100644
index 0000000000..1a907ab8e6
--- /dev/null
+++ b/plugins/graphiql/src/setupTests.ts
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import '@testing-library/jest-dom/extend-expect';
+require('jest-fetch-mock').enableMocks();
diff --git a/plugins/graphiql/tsconfig.json b/plugins/graphiql/tsconfig.json
new file mode 100644
index 0000000000..55fa1e2384
--- /dev/null
+++ b/plugins/graphiql/tsconfig.json
@@ -0,0 +1,7 @@
+{
+ "extends": "../../tsconfig.json",
+ "include": ["src", "dev"],
+ "compilerOptions": {
+ "baseUrl": "src"
+ }
+}
diff --git a/yarn.lock b/yarn.lock
index d30e71ad42..5126cfa721 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1166,7 +1166,7 @@
"@emotion/utils" "0.11.3"
"@emotion/weak-memoize" "0.2.5"
-"@emotion/core@^10.0.20":
+"@emotion/core@^10.0.0", "@emotion/core@^10.0.20", "@emotion/core@^10.0.28":
version "10.0.28"
resolved "https://registry.npmjs.org/@emotion/core/-/core-10.0.28.tgz#bb65af7262a234593a9e952c041d0f1c9b9bef3d"
integrity sha512-pH8UueKYO5jgg0Iq+AmCLxBsvuGtvlmiDCOuv8fGNYn3cowFpLN98L8zO56U0H1PjDIyAlXymgL3Wu7u7v6hbA==
@@ -1192,14 +1192,14 @@
resolved "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413"
integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==
-"@emotion/is-prop-valid@0.8.8":
+"@emotion/is-prop-valid@0.8.8", "@emotion/is-prop-valid@^0.8.1":
version "0.8.8"
resolved "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz#db28b1c4368a259b60a97311d6a952d4fd01ac1a"
integrity sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==
dependencies:
"@emotion/memoize" "0.7.4"
-"@emotion/memoize@0.7.4":
+"@emotion/memoize@0.7.4", "@emotion/memoize@^0.7.1":
version "0.7.4"
resolved "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz#19bf0f5af19149111c40d98bb0cf82119f5d9eeb"
integrity sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==
@@ -1230,7 +1230,7 @@
"@emotion/serialize" "^0.11.15"
"@emotion/utils" "0.11.3"
-"@emotion/styled@^10.0.17":
+"@emotion/styled@^10.0.0", "@emotion/styled@^10.0.17":
version "10.0.27"
resolved "https://registry.npmjs.org/@emotion/styled/-/styled-10.0.27.tgz#12cb67e91f7ad7431e1875b1d83a94b814133eaf"
integrity sha512-iK/8Sh7+NLJzyp9a5+vIQIXTYxfT4yB/OJbjzQanB2RZpvmzBQOHZWhpAMZWYEKRNNbsD6WfBw5sVWkb6WzS/Q==
@@ -2491,6 +2491,11 @@
prop-types "^15.7.2"
react-is "^16.8.0"
+"@mdx-js/react@^1.0.0", "@mdx-js/react@^1.5.2":
+ version "1.5.9"
+ resolved "https://registry.npmjs.org/@mdx-js/react/-/react-1.5.9.tgz#31873ab097fbe58c61c7585fc0be64e83182b6df"
+ integrity sha512-rengdUSedIdIQbXPSeafItCacTYocARAjUA51b6R1KNHmz+59efz7UmyTKr73viJQZ98ouu7iRGmOTtjRrbbWA==
+
"@mrmlnc/readdir-enhanced@^2.2.1":
version "2.2.1"
resolved "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde"
@@ -3401,6 +3406,105 @@
telejson "^3.2.0"
util-deprecate "^1.0.2"
+"@styled-system/background@^5.1.2":
+ version "5.1.2"
+ resolved "https://registry.npmjs.org/@styled-system/background/-/background-5.1.2.tgz#75c63d06b497ab372b70186c0bf608d62847a2ba"
+ integrity sha512-jtwH2C/U6ssuGSvwTN3ri/IyjdHb8W9X/g8Y0JLcrH02G+BW3OS8kZdHphF1/YyRklnrKrBT2ngwGUK6aqqV3A==
+ dependencies:
+ "@styled-system/core" "^5.1.2"
+
+"@styled-system/border@^5.1.5":
+ version "5.1.5"
+ resolved "https://registry.npmjs.org/@styled-system/border/-/border-5.1.5.tgz#0493d4332d2b59b74bb0d57d08c73eb555761ba6"
+ integrity sha512-JvddhNrnhGigtzWRCVuAHepniyVi6hBlimxWDVAdcTuk7aRn9BYJUwfHslURtwYFsF5FoEs8Zmr1oZq2M1AP0A==
+ dependencies:
+ "@styled-system/core" "^5.1.2"
+
+"@styled-system/color@^5.1.2":
+ version "5.1.2"
+ resolved "https://registry.npmjs.org/@styled-system/color/-/color-5.1.2.tgz#b8d6b4af481faabe4abca1a60f8daa4ccc2d9f43"
+ integrity sha512-1kCkeKDZkt4GYkuFNKc7vJQMcOmTl3bJY3YBUs7fCNM6mMYJeT1pViQ2LwBSBJytj3AB0o4IdLBoepgSgGl5MA==
+ dependencies:
+ "@styled-system/core" "^5.1.2"
+
+"@styled-system/core@^5.1.2":
+ version "5.1.2"
+ resolved "https://registry.npmjs.org/@styled-system/core/-/core-5.1.2.tgz#b8b7b86455d5a0514f071c4fa8e434b987f6a772"
+ integrity sha512-XclBDdNIy7OPOsN4HBsawG2eiWfCcuFt6gxKn1x4QfMIgeO6TOlA2pZZ5GWZtIhCUqEPTgIBta6JXsGyCkLBYw==
+ dependencies:
+ object-assign "^4.1.1"
+
+"@styled-system/css@^5.1.5":
+ version "5.1.5"
+ resolved "https://registry.npmjs.org/@styled-system/css/-/css-5.1.5.tgz#0460d5f3ff962fa649ea128ef58d9584f403bbbc"
+ integrity sha512-XkORZdS5kypzcBotAMPBoeckDs9aSZVkvrAlq5K3xP8IMAUek+x2O4NtwoSgkYkWWzVBu6DGdFZLR790QWGG+A==
+
+"@styled-system/flexbox@^5.1.2":
+ version "5.1.2"
+ resolved "https://registry.npmjs.org/@styled-system/flexbox/-/flexbox-5.1.2.tgz#077090f43f61c3852df63da24e4108087a8beecf"
+ integrity sha512-6hHV52+eUk654Y1J2v77B8iLeBNtc+SA3R4necsu2VVinSD7+XY5PCCEzBFaWs42dtOEDIa2lMrgL0YBC01mDQ==
+ dependencies:
+ "@styled-system/core" "^5.1.2"
+
+"@styled-system/grid@^5.1.2":
+ version "5.1.2"
+ resolved "https://registry.npmjs.org/@styled-system/grid/-/grid-5.1.2.tgz#7165049877732900b99cd00759679fbe45c6c573"
+ integrity sha512-K3YiV1KyHHzgdNuNlaw8oW2ktMuGga99o1e/NAfTEi5Zsa7JXxzwEnVSDSBdJC+z6R8WYTCYRQC6bkVFcvdTeg==
+ dependencies:
+ "@styled-system/core" "^5.1.2"
+
+"@styled-system/layout@^5.1.2":
+ version "5.1.2"
+ resolved "https://registry.npmjs.org/@styled-system/layout/-/layout-5.1.2.tgz#12d73e79887e10062f4dbbbc2067462eace42339"
+ integrity sha512-wUhkMBqSeacPFhoE9S6UF3fsMEKFv91gF4AdDWp0Aym1yeMPpqz9l9qS/6vjSsDPF7zOb5cOKC3tcKKOMuDCPw==
+ dependencies:
+ "@styled-system/core" "^5.1.2"
+
+"@styled-system/position@^5.1.2":
+ version "5.1.2"
+ resolved "https://registry.npmjs.org/@styled-system/position/-/position-5.1.2.tgz#56961266566836f57a24d8e8e33ce0c1adb59dd3"
+ integrity sha512-60IZfMXEOOZe3l1mCu6sj/2NAyUmES2kR9Kzp7s2D3P4qKsZWxD1Se1+wJvevb+1TP+ZMkGPEYYXRyU8M1aF5A==
+ dependencies:
+ "@styled-system/core" "^5.1.2"
+
+"@styled-system/shadow@^5.1.2":
+ version "5.1.2"
+ resolved "https://registry.npmjs.org/@styled-system/shadow/-/shadow-5.1.2.tgz#beddab28d7de03cd0177a87ac4ed3b3b6d9831fd"
+ integrity sha512-wqniqYb7XuZM7K7C0d1Euxc4eGtqEe/lvM0WjuAFsQVImiq6KGT7s7is+0bNI8O4Dwg27jyu4Lfqo/oIQXNzAg==
+ dependencies:
+ "@styled-system/core" "^5.1.2"
+
+"@styled-system/should-forward-prop@^5.1.2":
+ version "5.1.5"
+ resolved "https://registry.npmjs.org/@styled-system/should-forward-prop/-/should-forward-prop-5.1.5.tgz#c392008c6ae14a6eb78bf1932733594f7f7e5c76"
+ integrity sha512-+rPRomgCGYnUIaFabDoOgpSDc4UUJ1KsmlnzcEp0tu5lFrBQKgZclSo18Z1URhaZm7a6agGtS5Xif7tuC2s52Q==
+ dependencies:
+ "@emotion/is-prop-valid" "^0.8.1"
+ "@emotion/memoize" "^0.7.1"
+ styled-system "^5.1.5"
+
+"@styled-system/space@^5.1.2":
+ version "5.1.2"
+ resolved "https://registry.npmjs.org/@styled-system/space/-/space-5.1.2.tgz#38925d2fa29a41c0eb20e65b7c3efb6e8efce953"
+ integrity sha512-+zzYpR8uvfhcAbaPXhH8QgDAV//flxqxSjHiS9cDFQQUSznXMQmxJegbhcdEF7/eNnJgHeIXv1jmny78kipgBA==
+ dependencies:
+ "@styled-system/core" "^5.1.2"
+
+"@styled-system/typography@^5.1.2":
+ version "5.1.2"
+ resolved "https://registry.npmjs.org/@styled-system/typography/-/typography-5.1.2.tgz#65fb791c67d50cd2900d234583eaacdca8c134f7"
+ integrity sha512-BxbVUnN8N7hJ4aaPOd7wEsudeT7CxarR+2hns8XCX1zp0DFfbWw4xYa/olA0oQaqx7F1hzDg+eRaGzAJbF+jOg==
+ dependencies:
+ "@styled-system/core" "^5.1.2"
+
+"@styled-system/variant@^5.1.5":
+ version "5.1.5"
+ resolved "https://registry.npmjs.org/@styled-system/variant/-/variant-5.1.5.tgz#8446d8aad06af3a4c723d717841df2dbe4ddeafd"
+ integrity sha512-Yn8hXAFoWIro8+Q5J8YJd/mP85Teiut3fsGVR9CAxwgNfIAiqlYxsk5iHU7VHJks/0KjL4ATSjmbtCDC/4l1qw==
+ dependencies:
+ "@styled-system/core" "^5.1.2"
+ "@styled-system/css" "^5.1.5"
+
"@svgr/babel-plugin-add-jsx-attribute@^4.2.0":
version "4.2.0"
resolved "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-4.2.0.tgz#dadcb6218503532d6884b210e7f3c502caaa44b1"
@@ -3566,6 +3670,61 @@
resolved "https://registry.npmjs.org/@testing-library/user-event/-/user-event-7.2.1.tgz#2ad4e844175a3738cb9e7064be5ea070b8863a1c"
integrity sha512-oZ0Ib5I4Z2pUEcoo95cT1cr6slco9WY7yiPpG+RGNkj8YcYgJnM7pXmYmorNOReh8MIGcKSqXyeGjxnr8YiZbA==
+"@theme-ui/color-modes@^0.3.1":
+ version "0.3.1"
+ resolved "https://registry.npmjs.org/@theme-ui/color-modes/-/color-modes-0.3.1.tgz#8c2b18fb170e6c998287b7381240a8b9cca8b0d1"
+ integrity sha512-WuZGgFW7M5wOWSse1PVZCEfM0OZip15/D6U3bB3B9KmWax7qiSnAm1yAMLRQKC+QYhndrjq3xU+WAQm11KnhIw==
+ dependencies:
+ "@emotion/core" "^10.0.0"
+ "@theme-ui/core" "^0.3.1"
+ "@theme-ui/css" "^0.3.1"
+ deepmerge "^4.2.2"
+
+"@theme-ui/components@^0.3.1":
+ version "0.3.1"
+ resolved "https://registry.npmjs.org/@theme-ui/components/-/components-0.3.1.tgz#fe023e156c1e1c076d5f2258466426e94adc2765"
+ integrity sha512-uG4dUM61s4tWv6N34uxs5VIh24bJyA/7TrYJ75WDiI+s72zbcNG7aGRpvX/hSZnAhxjdXpuskdEM3eEgOabdEg==
+ dependencies:
+ "@emotion/core" "^10.0.0"
+ "@emotion/styled" "^10.0.0"
+ "@styled-system/color" "^5.1.2"
+ "@styled-system/should-forward-prop" "^5.1.2"
+ "@styled-system/space" "^5.1.2"
+ "@theme-ui/css" "^0.3.1"
+
+"@theme-ui/core@^0.3.1":
+ version "0.3.1"
+ resolved "https://registry.npmjs.org/@theme-ui/core/-/core-0.3.1.tgz#dbe9800b9d6e923e1a7417e6adebce21524f8c02"
+ integrity sha512-cK6EVSOx0Kyx1Xpi4qb0JTLIxywx0DRh+53Ln1foXMplF2qKaDsFi3vD6duHIlT331E3CNOa9dftHHNM7y4rbA==
+ dependencies:
+ "@emotion/core" "^10.0.0"
+ "@theme-ui/css" "^0.3.1"
+ deepmerge "^4.2.2"
+
+"@theme-ui/css@^0.3.1":
+ version "0.3.1"
+ resolved "https://registry.npmjs.org/@theme-ui/css/-/css-0.3.1.tgz#b85c7e8fae948dc0de65aa30b853368993e25cb3"
+ integrity sha512-QB2/fZBpo4inaLHL3OrB8NOBgNfwnj8GtHzXWHb9iQSRjmtNX8zPXBe32jLT7qQP0+y8JxPT4YChZIkm5ZyIdg==
+
+"@theme-ui/mdx@^0.3.0":
+ version "0.3.0"
+ resolved "https://registry.npmjs.org/@theme-ui/mdx/-/mdx-0.3.0.tgz#8bb1342204acfaa69914d6b6567c5c49d9a8c1e6"
+ integrity sha512-/GHBNKqmUptWwkmF+zIASVQtjYs81XMEwtqPCHnHuaaCzhZxcXrtCwvcAgmCXF8hpRttCXVVxw1X3Gt0mhzaTQ==
+ dependencies:
+ "@emotion/core" "^10.0.0"
+ "@emotion/styled" "^10.0.0"
+ "@mdx-js/react" "^1.0.0"
+
+"@theme-ui/theme-provider@^0.3.1":
+ version "0.3.1"
+ resolved "https://registry.npmjs.org/@theme-ui/theme-provider/-/theme-provider-0.3.1.tgz#910bc43454fd61b1047d7bb0dce05e36ffb6b44b"
+ integrity sha512-Sjj6lD0gPxBi+hcGCkawcGZECeESV/mW2YfmPqjNgmc296x5tulfNc+0/N5CJwLVOmnkn8zR5KNWZ8BjndfeTg==
+ dependencies:
+ "@emotion/core" "^10.0.0"
+ "@theme-ui/color-modes" "^0.3.1"
+ "@theme-ui/core" "^0.3.1"
+ "@theme-ui/mdx" "^0.3.0"
+
"@tootallnate/once@1":
version "1.0.0"
resolved "https://registry.npmjs.org/@tootallnate/once/-/once-1.0.0.tgz#9c13c2574c92d4503b005feca8f2e16cc1611506"
@@ -4483,6 +4642,11 @@
resolved "https://registry.npmjs.org/@xobotyi/scrollbar-width/-/scrollbar-width-1.9.4.tgz#a7dce20b7465bcad29cd6bbb557695e4ea7863cb"
integrity sha512-o12FCQt/X5n3pgKEWGpt0f/7Eg4mfv3uRwPUrctiOT8ZuxbH3cNLGWfH/8y6KxVJg4L2885ucuXQ6XECZzUiJA==
+"@xobotyi/scrollbar-width@1.9.5":
+ version "1.9.5"
+ resolved "https://registry.npmjs.org/@xobotyi/scrollbar-width/-/scrollbar-width-1.9.5.tgz#80224a6919272f405b87913ca13b92929bdf3c4d"
+ integrity sha512-N8tkAACJx2ww8vFMneJmaAgmjAG1tnVBZJRLRcx061tmsLRZHSEZSLuGWnwPtunsSLvSqXQ2wfp7Mgqg1I+2dQ==
+
"@xtuc/ieee754@^1.2.0":
version "1.2.0"
resolved "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790"
@@ -6473,6 +6637,19 @@ code-point-at@^1.0.0:
resolved "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=
+codemirror-graphql@^0.12.0-alpha.7:
+ version "0.12.0-alpha.7"
+ resolved "https://registry.npmjs.org/codemirror-graphql/-/codemirror-graphql-0.12.0-alpha.7.tgz#fb8a8e633f5e416a9736df2fa697312a0955db20"
+ integrity sha512-LOsHnAc/pWOqqUEfQX5tNn10jStqIe8il6/vHq7m81uyGcp7tx5Np3O7zwGKQ/HdewDUMjeqXnva5tFGYaKzVg==
+ dependencies:
+ graphql-language-service-interface "^2.4.0-alpha.7"
+ graphql-language-service-parser "^1.6.0-alpha.3"
+
+codemirror@^5.52.2:
+ version "5.53.2"
+ resolved "https://registry.npmjs.org/codemirror/-/codemirror-5.53.2.tgz#9799121cf8c50809cca487304e9de3a74d33f428"
+ integrity sha512-wvSQKS4E+P8Fxn/AQ+tQtJnF1qH5UOlxtugFLpubEZ5jcdH2iXTVinb+Xc/4QjshuOxRm4fUsU2QPF1JJKiyXA==
+
collapse-white-space@^1.0.2:
version "1.0.6"
resolved "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.6.tgz#e63629c0016665792060dbbeb79c42239d2c5287"
@@ -7618,6 +7795,11 @@ deep-object-diff@^1.1.0:
resolved "https://registry.npmjs.org/deep-object-diff/-/deep-object-diff-1.1.0.tgz#d6fabf476c2ed1751fc94d5ca693d2ed8c18bc5a"
integrity sha512-b+QLs5vHgS+IoSNcUE4n9HP2NwcHj7aqnJWsjPtuG75Rh5TOaGt0OjAYInh77d5T16V5cRDC+Pw/6ZZZiETBGw==
+deepmerge@^4.2.2:
+ version "4.2.2"
+ resolved "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955"
+ integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==
+
default-gateway@^4.2.0:
version "4.2.0"
resolved "https://registry.npmjs.org/default-gateway/-/default-gateway-4.2.0.tgz#167104c7500c2115f6dd69b0a536bb8ed720552b"
@@ -8188,7 +8370,7 @@ entities@^1.1.1, entities@^1.1.2:
resolved "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56"
integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==
-entities@^2.0.0:
+entities@^2.0.0, entities@~2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz#68d6084cab1b079767540d80e56a39b423e4abf4"
integrity sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw==
@@ -9968,6 +10150,55 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.3
resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423"
integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==
+graphiql@^1.0.0-alpha.8:
+ version "1.0.0-alpha.8"
+ resolved "https://registry.npmjs.org/graphiql/-/graphiql-1.0.0-alpha.8.tgz#a9cc594a8666e372c919a5c86a32835bc37499ff"
+ integrity sha512-6cR4NUtR79P2ShXt2P5d4OSIlsqiHzb7fK27LSm4JHIx0uBLYWrlJwHcjjF+Ucujr3fbVn4miyNF+ypvMJp53g==
+ dependencies:
+ "@emotion/core" "^10.0.28"
+ "@mdx-js/react" "^1.5.2"
+ codemirror "^5.52.2"
+ codemirror-graphql "^0.12.0-alpha.7"
+ copy-to-clipboard "^3.2.0"
+ entities "^2.0.0"
+ markdown-it "^10.0.0"
+ regenerator-runtime "^0.13.5"
+ theme-ui "^0.3.1"
+
+graphql-language-service-interface@^2.4.0-alpha.7:
+ version "2.4.0-alpha.7"
+ resolved "https://registry.npmjs.org/graphql-language-service-interface/-/graphql-language-service-interface-2.4.0-alpha.7.tgz#5458f1f17a79dde5b51dab0d21eda63dff48a918"
+ integrity sha512-X5jwTI4AlcKB/t9/hZBn9O69uG9WPbkFnZivhNfztzeudKV+cXHYR6behsR47bR2nzF3YEu7Nv+3HExXKQAlWg==
+ dependencies:
+ graphql-language-service-parser "^1.6.0-alpha.3"
+ graphql-language-service-types "^1.6.0-alpha.5"
+ graphql-language-service-utils "^2.4.0-alpha.6"
+ vscode-languageserver-types "^3.15.1"
+
+graphql-language-service-parser@^1.6.0-alpha.3:
+ version "1.6.0-alpha.3"
+ resolved "https://registry.npmjs.org/graphql-language-service-parser/-/graphql-language-service-parser-1.6.0-alpha.3.tgz#671643018fb4b24f409997a05b021030948562fb"
+ integrity sha512-gx2u6b2m9X9DjvlfEjmBQ67GtZxPPWAtVb63BQ21u2MPxqYjKsBJkKLq9PiC2u57bJhv+h4MoL4OLJ/vkmq6Ig==
+ dependencies:
+ graphql-language-service-types "^1.6.0-alpha.5"
+
+graphql-language-service-types@^1.6.0-alpha.5:
+ version "1.6.0-alpha.5"
+ resolved "https://registry.npmjs.org/graphql-language-service-types/-/graphql-language-service-types-1.6.0-alpha.5.tgz#113a92c7544d98c8a8b8c3e04c9f982d3dbe1a00"
+ integrity sha512-Q/pTif29xM6OiFV9RsYLwX2uDeCMdSG36n4G0aDvfbWxbOBj48vSlLL5R8Gpt/DjocG9Kkv51CZay6pMPtmAfg==
+
+graphql-language-service-utils@^2.4.0-alpha.6:
+ version "2.4.0-alpha.6"
+ resolved "https://registry.npmjs.org/graphql-language-service-utils/-/graphql-language-service-utils-2.4.0-alpha.6.tgz#5c3b30150e4905517b84b71f84956851c2c883e1"
+ integrity sha512-/+crYcPhOoeu1qpHhH2FZpI7w4i3q4Kq7jzbodXxOZBAqJFd3FSHTnVBYEAfgTgkTbIC7yIXVwnIwXtqDFTNDQ==
+ dependencies:
+ graphql-language-service-types "^1.6.0-alpha.5"
+
+graphql@15.0.0:
+ version "15.0.0"
+ resolved "https://registry.npmjs.org/graphql/-/graphql-15.0.0.tgz#042a5eb5e2506a2e2111ce41eb446a8e570b8be9"
+ integrity sha512-ZyVO1xIF9F+4cxfkdhOJINM+51B06Friuv4M66W7HzUOeFd+vNzUn4vtswYINPi6sysjf1M2Ri/rwZALqgwbaQ==
+
growly@^1.3.0:
version "1.3.0"
resolved "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
@@ -12910,6 +13141,13 @@ lines-and-columns@^1.1.6:
resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00"
integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=
+linkify-it@^2.0.0:
+ version "2.2.0"
+ resolved "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz#e3b54697e78bf915c70a38acd78fd09e0058b1cf"
+ integrity sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==
+ dependencies:
+ uc.micro "^1.0.1"
+
lint-staged@^10.0.4:
version "10.0.8"
resolved "https://registry.npmjs.org/lint-staged/-/lint-staged-10.0.8.tgz#0f7849cdc336061f25f5d4fcbcfa385701ff4739"
@@ -13464,6 +13702,17 @@ markdown-escapes@^1.0.0:
resolved "https://registry.npmjs.org/markdown-escapes/-/markdown-escapes-1.0.4.tgz#c95415ef451499d7602b91095f3c8e8975f78535"
integrity sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==
+markdown-it@^10.0.0:
+ version "10.0.0"
+ resolved "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz#abfc64f141b1722d663402044e43927f1f50a8dc"
+ integrity sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==
+ dependencies:
+ argparse "^1.0.7"
+ entities "~2.0.0"
+ linkify-it "^2.0.0"
+ mdurl "^1.0.1"
+ uc.micro "^1.0.5"
+
markdown-to-jsx@^6.9.1, markdown-to-jsx@^6.9.3:
version "6.11.0"
resolved "https://registry.npmjs.org/markdown-to-jsx/-/markdown-to-jsx-6.11.0.tgz#a2e3f2bc781c3402d8bb0f8e0a12a186474623b0"
@@ -13515,6 +13764,11 @@ mdn-data@2.0.6:
resolved "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.6.tgz#852dc60fcaa5daa2e8cf6c9189c440ed3e042978"
integrity sha512-rQvjv71olwNHgiTbfPZFkJtjNMciWgswYeciZhtvWLO8bmX3TnhyA62I6sTWOyZssWHJJjY6/KiWwqQsWWsqOA==
+mdurl@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e"
+ integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=
+
meant@~1.0.1:
version "1.0.1"
resolved "https://registry.npmjs.org/meant/-/meant-1.0.1.tgz#66044fea2f23230ec806fb515efea29c44d2115d"
@@ -16967,6 +17221,25 @@ react-transition-group@^4.3.0:
loose-envify "^1.4.0"
prop-types "^15.6.2"
+react-use@^13.0.0:
+ version "13.27.1"
+ resolved "https://registry.npmjs.org/react-use/-/react-use-13.27.1.tgz#e2ae2b708dafc7893c4772628801589aab9de370"
+ integrity sha512-bAwdqDMXs5lovEanXnL1izledfrPEUUv1afoTVB59eUiYcDyKul+M/dT/2WcgHjoY/R6QlrTcZoW4R7ifwvBfw==
+ dependencies:
+ "@types/js-cookie" "2.2.5"
+ "@xobotyi/scrollbar-width" "1.9.5"
+ copy-to-clipboard "^3.2.0"
+ fast-deep-equal "^3.1.1"
+ fast-shallow-equal "^1.0.0"
+ js-cookie "^2.2.1"
+ nano-css "^5.2.1"
+ resize-observer-polyfill "^1.5.1"
+ screenfull "^5.0.0"
+ set-harmonic-interval "^1.0.1"
+ throttle-debounce "^2.1.0"
+ ts-easing "^0.2.0"
+ tslib "^1.10.0"
+
react-use@^13.24.0:
version "13.27.0"
resolved "https://registry.npmjs.org/react-use/-/react-use-13.27.0.tgz#53a619dc9213e2cbe65d6262e8b0e76641ade4aa"
@@ -17290,7 +17563,7 @@ regenerator-runtime@^0.11.0:
resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
-regenerator-runtime@^0.13.2, regenerator-runtime@^0.13.3, regenerator-runtime@^0.13.4:
+regenerator-runtime@^0.13.2, regenerator-runtime@^0.13.3, regenerator-runtime@^0.13.4, regenerator-runtime@^0.13.5:
version "0.13.5"
resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz#d878a1d094b4306d10b9096484b33ebd55e26697"
integrity sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA==
@@ -19023,6 +19296,25 @@ style-loader@^1.0.0:
loader-utils "^1.2.3"
schema-utils "^2.6.4"
+styled-system@^5.1.5:
+ version "5.1.5"
+ resolved "https://registry.npmjs.org/styled-system/-/styled-system-5.1.5.tgz#e362d73e1dbb5641a2fd749a6eba1263dc85075e"
+ integrity sha512-7VoD0o2R3RKzOzPK0jYrVnS8iJdfkKsQJNiLRDjikOpQVqQHns/DXWaPZOH4tIKkhAT7I6wIsy9FWTWh2X3q+A==
+ dependencies:
+ "@styled-system/background" "^5.1.2"
+ "@styled-system/border" "^5.1.5"
+ "@styled-system/color" "^5.1.2"
+ "@styled-system/core" "^5.1.2"
+ "@styled-system/flexbox" "^5.1.2"
+ "@styled-system/grid" "^5.1.2"
+ "@styled-system/layout" "^5.1.2"
+ "@styled-system/position" "^5.1.2"
+ "@styled-system/shadow" "^5.1.2"
+ "@styled-system/space" "^5.1.2"
+ "@styled-system/typography" "^5.1.2"
+ "@styled-system/variant" "^5.1.5"
+ object-assign "^4.1.1"
+
stylehacks@^4.0.0:
version "4.0.3"
resolved "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz#6718fcaf4d1e07d8a1318690881e8d96726a71d5"
@@ -19294,6 +19586,18 @@ text-table@0.2.0, text-table@^0.2.0, text-table@~0.2.0:
resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=
+theme-ui@^0.3.1:
+ version "0.3.1"
+ resolved "https://registry.npmjs.org/theme-ui/-/theme-ui-0.3.1.tgz#b00ee2c03eb3d820536af8b121c64d13b3777cf0"
+ integrity sha512-My/TSALqp7Dst5Ez7nJA+94Q8zJhc26Z0qGo8kEWyoqHHJ5TU8xdhjLPBltTdQck3T32cSq5USIeSKU3JtxYUQ==
+ dependencies:
+ "@theme-ui/color-modes" "^0.3.1"
+ "@theme-ui/components" "^0.3.1"
+ "@theme-ui/core" "^0.3.1"
+ "@theme-ui/css" "^0.3.1"
+ "@theme-ui/mdx" "^0.3.0"
+ "@theme-ui/theme-provider" "^0.3.1"
+
thenify-all@^1.0.0:
version "1.6.0"
resolved "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726"
@@ -19722,6 +20026,11 @@ ua-parser-js@^0.7.18:
resolved "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.21.tgz#853cf9ce93f642f67174273cc34565ae6f308777"
integrity sha512-+O8/qh/Qj8CgC6eYBVBykMrNtp5Gebn4dlGD/kKXVkJNDwyrAwSIqwz8CDf+tsAIWVycKcku6gIXJ0qwx/ZXaQ==
+uc.micro@^1.0.1, uc.micro@^1.0.5:
+ version "1.0.6"
+ resolved "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac"
+ integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==
+
uglify-js@3.4.x:
version "3.4.10"
resolved "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz#9ad9563d8eb3acdfb8d38597d2af1d815f6a755f"
@@ -20176,6 +20485,11 @@ vm-browserify@^1.0.1:
resolved "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0"
integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==
+vscode-languageserver-types@^3.15.1:
+ version "3.15.1"
+ resolved "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.15.1.tgz#17be71d78d2f6236d414f0001ce1ef4d23e6b6de"
+ integrity sha512-+a9MPUQrNGRrGU630OGbYVQ+11iOIovjCkqxajPa9w57Sd5ruK8WQNsslzpa0x/QJqC8kRc2DUxWjIFwoNm4ZQ==
+
w3c-hr-time@^1.0.1:
version "1.0.2"
resolved "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd"