Working local

This commit is contained in:
Bel Curcio 2021-06-11 12:01:51 -03:00
parent 23b69ec442
commit 6de60ce29c
35 changed files with 11125 additions and 15938 deletions

View File

@ -72,9 +72,8 @@ export type APIProvider = {
operations: APIOperations<any> operations: APIOperations<any>
} }
export type CommerceAPI< export type CommerceAPI<P extends APIProvider = APIProvider> =
P extends APIProvider = APIProvider CommerceAPICore<P> & AllOperations<P>
> = CommerceAPICore<P> & AllOperations<P>
export class CommerceAPICore<P extends APIProvider = APIProvider> { export class CommerceAPICore<P extends APIProvider = APIProvider> {
constructor(readonly provider: P) {} constructor(readonly provider: P) {}
@ -134,17 +133,17 @@ export function getEndpoint<
} }
} }
export const createEndpoint = <API extends GetAPISchema<any, any>>( export const createEndpoint =
endpoint: API['endpoint'] <API extends GetAPISchema<any, any>>(endpoint: API['endpoint']) =>
) => <P extends APIProvider>( <P extends APIProvider>(
commerce: CommerceAPI<P>, commerce: CommerceAPI<P>,
context?: Partial<API['endpoint']> & { context?: Partial<API['endpoint']> & {
config?: P['config'] config?: P['config']
options?: API['schema']['endpoint']['options'] options?: API['schema']['endpoint']['options']
} }
): NextApiHandler => { ): NextApiHandler => {
return getEndpoint(commerce, { ...endpoint, ...context }) return getEndpoint(commerce, { ...endpoint, ...context })
} }
export interface CommerceAPIConfig { export interface CommerceAPIConfig {
locale?: string locale?: string

View File

@ -69,14 +69,6 @@ function withCommerceConfig(nextConfig = {}) {
}, exclude) }, exclude)
} }
if (process.env.COMMERCE_PROVIDER == 'local') {
tsconfig.exclude = tsconfig.exclude.concat(
'components/cart',
'components/auth',
'components/wishlist'
)
}
fs.writeFileSync( fs.writeFileSync(
tsconfigPath, tsconfigPath,
prettier.format(JSON.stringify(tsconfig), { parser: 'json' }) prettier.format(JSON.stringify(tsconfig), { parser: 'json' })

View File

@ -1 +0,0 @@
COMMERCE_PROVIDER=local

View File

@ -1 +0,0 @@
## Local Provider

View File

@ -1,32 +0,0 @@
import {
CommerceAPI,
CommerceAPIConfig,
getCommerceApi as commerceApi,
} from '@commerce/api'
export interface LocalConfig extends CommerceAPIConfig {}
import * as operations from './operations'
import fetchGraphqlApi from './utils/fetch-graphql-api'
const config: LocalConfig = {
commerceUrl: '',
apiToken: '',
customerCookie: '',
cartCookie: '',
cartCookieMaxAge: 16000000,
fetch: fetchGraphqlApi,
}
export const provider = {
config,
operations,
}
export type Provider = typeof provider
export type LocalAPI<P extends Provider = Provider> = CommerceAPI<P>
export function getCommerceApi<P extends Provider>(
customProvider: P = provider as any
): LocalAPI<P> {
return commerceApi(customProvider)
}

View File

@ -1,67 +0,0 @@
import type {
OperationContext,
OperationOptions,
} from '@commerce/api/operations'
import {
GetAllPagesQuery,
GetAllPagesQueryVariables,
PageEdge,
} from '../../schema'
import { normalizePages } from '../../utils'
import type { ShopifyConfig, Provider } from '..'
import type { GetAllPagesOperation, Page } from '../../types/page'
import getAllPagesQuery from '../../utils/queries/get-all-pages-query'
export default function getAllPagesOperation({
commerce,
}: OperationContext<Provider>) {
async function getAllPages<T extends GetAllPagesOperation>(opts?: {
config?: Partial<ShopifyConfig>
preview?: boolean
}): Promise<T['data']>
async function getAllPages<T extends GetAllPagesOperation>(
opts: {
config?: Partial<ShopifyConfig>
preview?: boolean
} & OperationOptions
): Promise<T['data']>
async function getAllPages<T extends GetAllPagesOperation>({
query = getAllPagesQuery,
config,
variables,
}: {
url?: string
config?: Partial<ShopifyConfig>
variables?: GetAllPagesQueryVariables
preview?: boolean
query?: string
} = {}): Promise<T['data']> {
const { fetch, locale, locales = ['en-US'] } = commerce.getConfig(config)
const { data } = await fetch<GetAllPagesQuery, GetAllPagesQueryVariables>(
query,
{
variables,
},
{
...(locale && {
headers: {
'Accept-Language': locale,
},
}),
}
)
return {
pages: locales.reduce<Page[]>(
(arr, locale) =>
arr.concat(normalizePages(data.pages.edges as PageEdge[], locale)),
[]
),
}
}
return getAllPages
}

View File

@ -1,27 +0,0 @@
import type { LocalConfig, Provider } from '..'
import type { OperationContext } from '@commerce/api/operations'
import { GetAllProductPathsOperation } from '../../types/product'
export default function getAllProductPathsOperation({
commerce,
}: OperationContext<Provider>) {
async function getAllProductPaths<T extends GetAllProductPathsOperation>({
query,
config,
variables,
}: {
query?: string
config?: LocalConfig
variables?: T['variables']
} = {}): Promise<T['data']> {
return {
products: [
{
path: `/hank`,
},
],
}
}
return getAllProductPaths
}

View File

@ -1,33 +0,0 @@
import type { Provider } from '..'
import type { Product } from '@commerce/types/product'
import type { OperationContext } from '@commerce/api/operations'
export default function getAllProductsOperation({}: OperationContext<Provider>) {
async function getAllProducts(): Promise<{ products: Product[] }> {
const product = {
id: 'Z2lkOi8vc2hvcGlmeS9Qcm9kdWN0LzU0NDczMjUwMjQ0MjA=',
name: 'New Short Sleeve T-Shirt',
description: '',
vendor: 'Next.js',
path: '/new-short-sleeve-t-shirt',
slug: 'new-short-sleeve-t-shirt',
price: { value: 25, currencyCode: 'USD' },
images: [
{
url: '/assets/t-shirt-0.png',
altText: null,
width: 1000,
height: 1000,
},
],
variants: [],
options: [],
}
return {
products: [product],
}
}
return getAllProducts
}

View File

@ -1,64 +0,0 @@
import type {
OperationContext,
OperationOptions,
} from '@commerce/api/operations'
import { normalizePage } from '../../utils'
import type { ShopifyConfig, Provider } from '..'
import {
GetPageQuery,
GetPageQueryVariables,
Page as ShopifyPage,
} from '../../schema'
import { GetPageOperation } from '../../types/page'
import getPageQuery from '../../utils/queries/get-page-query'
export default function getPageOperation({
commerce,
}: OperationContext<Provider>) {
async function getPage<T extends GetPageOperation>(opts: {
variables: T['variables']
config?: Partial<ShopifyConfig>
preview?: boolean
}): Promise<T['data']>
async function getPage<T extends GetPageOperation>(
opts: {
variables: T['variables']
config?: Partial<ShopifyConfig>
preview?: boolean
} & OperationOptions
): Promise<T['data']>
async function getPage<T extends GetPageOperation>({
query = getPageQuery,
variables,
config,
}: {
query?: string
variables: T['variables']
config?: Partial<ShopifyConfig>
preview?: boolean
}): Promise<T['data']> {
const { fetch, locale = 'en-US' } = commerce.getConfig(config)
const {
data: { node: page },
} = await fetch<GetPageQuery, GetPageQueryVariables>(
query,
{
variables,
},
{
...(locale && {
headers: {
'Accept-Language': locale,
},
}),
}
)
return page ? { page: normalizePage(page as ShopifyPage, locale) } : {}
}
return getPage
}

View File

@ -1,11 +0,0 @@
import type { Product } from '@commerce/types/product'
export default function getProductOperation() {
async function getProduct(): Promise<Product | {} | any> {
return {
product: [],
}
}
return getProduct
}

View File

@ -1,62 +0,0 @@
import type {
OperationContext,
OperationOptions,
} from '@commerce/api/operations'
import { GetSiteInfoQueryVariables } from '../../schema'
import type { ShopifyConfig, Provider } from '..'
import { GetSiteInfoOperation } from '../../types/site'
import { getCategories, getBrands, getSiteInfoQuery } from '../../utils'
export default function getSiteInfoOperation({
commerce,
}: OperationContext<Provider>) {
async function getSiteInfo<T extends GetSiteInfoOperation>(opts?: {
config?: Partial<ShopifyConfig>
preview?: boolean
}): Promise<T['data']>
async function getSiteInfo<T extends GetSiteInfoOperation>(
opts: {
config?: Partial<ShopifyConfig>
preview?: boolean
} & OperationOptions
): Promise<T['data']>
async function getSiteInfo<T extends GetSiteInfoOperation>({
query = getSiteInfoQuery,
config,
variables,
}: {
query?: string
config?: Partial<ShopifyConfig>
preview?: boolean
variables?: GetSiteInfoQueryVariables
} = {}): Promise<T['data']> {
const cfg = commerce.getConfig(config)
const categories = await getCategories(cfg)
const brands = await getBrands(cfg)
/*
const { fetch, locale } = cfg
const { data } = await fetch<GetSiteInfoQuery, GetSiteInfoQueryVariables>(
query,
{ variables },
{
...(locale && {
headers: {
'Accept-Language': locale,
},
}),
}
)
*/
return {
categories,
brands,
}
}
return getSiteInfo
}

View File

@ -1,7 +0,0 @@
export { default as getAllPages } from './get-all-pages'
export { default as getPage } from './get-page'
export { default as getAllProducts } from './get-all-products'
export { default as getAllProductPaths } from './get-all-product-paths'
export { default as getProduct } from './get-product'
export { default as getSiteInfo } from './get-site-info'
export { default as login } from './login'

View File

@ -1,48 +0,0 @@
import type { ServerResponse } from 'http'
import type { OperationContext } from '@commerce/api/operations'
import type { LoginOperation } from '../../types/login'
import type { ShopifyConfig, Provider } from '..'
import {
customerAccessTokenCreateMutation,
setCustomerToken,
throwUserErrors,
} from '../../utils'
import { CustomerAccessTokenCreateMutation } from '../../schema'
export default function loginOperation({
commerce,
}: OperationContext<Provider>) {
async function login<T extends LoginOperation>({
query = customerAccessTokenCreateMutation,
variables,
config,
}: {
query?: string
variables: T['variables']
res: ServerResponse
config?: ShopifyConfig
}): Promise<T['data']> {
config = commerce.getConfig(config)
const {
data: { customerAccessTokenCreate },
} = await config.fetch<CustomerAccessTokenCreateMutation>(query, {
variables,
})
throwUserErrors(customerAccessTokenCreate?.customerUserErrors)
const customerAccessToken = customerAccessTokenCreate?.customerAccessToken
const accessToken = customerAccessToken?.accessToken
if (accessToken) {
setCustomerToken(accessToken)
}
return {
result: customerAccessToken?.accessToken,
}
}
return login
}

View File

@ -1,45 +0,0 @@
import type { GraphQLFetcher } from '@commerce/api'
import fetch from './fetch'
import { API_URL, API_TOKEN } from '../../const'
import { getError } from '../../utils/handle-fetch-response'
const fetchGraphqlApi: GraphQLFetcher = async (
query: string,
{ variables } = {},
fetchOptions
) => {
try {
const res = await fetch(API_URL, {
...fetchOptions,
method: 'POST',
headers: {
'X-Shopify-Storefront-Access-Token': API_TOKEN!,
...fetchOptions?.headers,
'Content-Type': 'application/json',
},
body: JSON.stringify({
query,
variables,
}),
})
const { data, errors, status } = await res.json()
if (errors) {
throw getError(errors, status)
}
return { data, res }
} catch (err) {
throw getError(
[
{
message: `${err} \n Most likely related to an unexpected output. e.g the store might be protected with password or not available.`,
},
],
500
)
}
}
export default fetchGraphqlApi

View File

@ -1,2 +0,0 @@
import zeitFetch from '@vercel/fetch'
export default zeitFetch()

View File

@ -1,8 +0,0 @@
{
"provider": "local",
"features": {
"cart": false,
"customer": false,
"wishlist": false
}
}

View File

@ -1,18 +0,0 @@
{
"id": "Z2lkOi8vc2hvcGlmeS9Qcm9kdWN0LzU0NDczMjUwMjQ0MjA=",
"name": "New Short Sleeve T-Shirt",
"vendor": "Next.js",
"path": "/new-short-sleeve-t-shirt",
"slug": "new-short-sleeve-t-shirt",
"price": { "value": 25, "currencyCode": "USD" },
"images": [
{
"url": "https://cdn.shopify.com/s/files/1/0434/0285/4564/products/short-sleeve-t-shirt-0.png?v=1622902418",
"altText": null,
"width": 1000,
"height": 1000
}
],
"variants": [],
"options": []
}

View File

@ -1,37 +0,0 @@
import React from 'react'
import {
CommerceConfig,
CommerceProvider as CoreCommerceProvider,
useCommerce as useCoreCommerce,
} from '@commerce'
import { localProvider } from './provider'
import type { LocalProvider } from './provider'
export { localProvider }
export type { LocalProvider }
export const localConfig: CommerceConfig = {
locale: 'en-us',
cartCookie: '',
}
export function CommerceProvider({
children,
...config
}: {
children?: React.ReactNode
locale: string
} & Partial<CommerceConfig>) {
return (
<CoreCommerceProvider
provider={localProvider}
config={{ ...localConfig, ...config }}
>
{children}
</CoreCommerceProvider>
)
}
export const useCommerce = () => useCoreCommerce<LocalProvider>()

View File

@ -1,5 +0,0 @@
const commerce = require('./commerce.config.json')
module.exports = {
commerce,
}

View File

@ -1,64 +0,0 @@
import { useMemo } from 'react'
import { useCommerce } from '..'
export function formatPrice({
amount,
currencyCode,
locale,
}: {
amount: number
currencyCode: string
locale: string
}) {
const formatCurrency = new Intl.NumberFormat(locale, {
style: 'currency',
currency: currencyCode,
})
return formatCurrency.format(amount)
}
export function formatVariantPrice({
amount,
baseAmount,
currencyCode,
locale,
}: {
baseAmount: number
amount: number
currencyCode: string
locale: string
}) {
const hasDiscount = baseAmount > amount
const formatDiscount = new Intl.NumberFormat(locale, { style: 'percent' })
const discount = hasDiscount
? formatDiscount.format((baseAmount - amount) / baseAmount)
: null
const price = formatPrice({ amount, currencyCode, locale })
const basePrice = hasDiscount
? formatPrice({ amount: baseAmount, currencyCode, locale })
: null
return { price, basePrice, discount }
}
export default function usePrice(
data?: {
amount: number
baseAmount?: number
currencyCode: string
} | null
) {
const { amount, baseAmount, currencyCode } = data ?? {}
const { locale } = useCommerce()
const value = useMemo(() => {
if (typeof amount !== 'number' || !currencyCode) return ''
return baseAmount
? formatVariantPrice({ amount, baseAmount, currencyCode, locale })
: formatPrice({ amount, currencyCode, locale })
}, [amount, baseAmount, currencyCode])
return typeof value === 'string' ? { price: value } : value
}

View File

@ -1,20 +0,0 @@
import { useHook, useSWRHook } from '../utils/use-hook'
import { SWRFetcher } from '../utils/default-fetcher'
import type { HookFetcherFn, SWRHook } from '../utils/types'
import type { SearchProductsHook } from '../types/product'
import type { Provider } from '..'
export type UseSearch<
H extends SWRHook<SearchProductsHook<any>> = SWRHook<SearchProductsHook>
> = ReturnType<H['useHook']>
export const fetcher: HookFetcherFn<SearchProductsHook> = SWRFetcher
const fn = (provider: Provider) => provider.products?.useSearch!
const useSearch: UseSearch = (input) => {
const hook = useHook(fn)
return useSWRHook({ fetcher, ...hook })(input)
}
export default useSearch

View File

@ -1,11 +0,0 @@
export const localProvider = {
locale: 'en-us',
cartCookie: '',
fetcher: () => {},
cart: {},
customer: {},
products: {},
auth: {},
}
export type LocalProvider = typeof localProvider

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
import type { APIProvider, CommerceAPIConfig } from '@commerce/api' import type { APIProvider, CommerceAPIConfig } from '@commerce/api'
import { CommerceAPI, getCommerceApi as commerceApi } from '@commerce/api' import { CommerceAPI, getCommerceApi as commerceApi } from '@commerce/api'
import fetchGraphqlApi from './utils/fetch-graphql-api' import fetcher from './utils/fetch-local'
import getAllPages from './operations/get-all-pages' import getAllPages from './operations/get-all-pages'
import getPage from './operations/get-page' import getPage from './operations/get-page'
@ -11,15 +11,13 @@ import getAllProducts from './operations/get-all-products'
import getProduct from './operations/get-product' import getProduct from './operations/get-product'
export interface LocalConfig extends CommerceAPIConfig {} export interface LocalConfig extends CommerceAPIConfig {}
const ONE_DAY = 60 * 60 * 24
const config: LocalConfig = { const config: LocalConfig = {
commerceUrl: '', commerceUrl: '',
apiToken: '', apiToken: '',
cartCookie: '', cartCookie: '',
customerCookie: '', customerCookie: '',
cartCookieMaxAge: ONE_DAY * 30, cartCookieMaxAge: 2592000,
fetch: fetchGraphqlApi, fetch: fetcher,
} }
const operations = { const operations = {

View File

@ -1,16 +1,25 @@
import { Product } from '@commerce/types/product' import { Product } from '@commerce/types/product'
import { GetAllProductsOperation } from '@commerce/types/product'
import type { OperationContext } from '@commerce/api/operations' import type { OperationContext } from '@commerce/api/operations'
import type { Provider } from '../index' import type { LocalConfig, Provider } from '../index'
import data from '../../data.json'
export type ProductVariables = { first?: number }
export default function getAllProductsOperation({ export default function getAllProductsOperation({
commerce, commerce,
}: OperationContext<Provider>) { }: OperationContext<Provider>) {
async function getAllProducts(): Promise<{ products: Product[] | any[] }> { async function getAllProducts<T extends GetAllProductsOperation>({
query = '',
variables,
config,
}: {
query?: string
variables?: T['variables']
config?: Partial<LocalConfig>
preview?: boolean
} = {}): Promise<{ products: Product[] | any[] }> {
console.log(data.products[0])
return Promise.resolve({ return Promise.resolve({
products: [], products: data.products,
}) })
} }
return getAllProducts return getAllProducts

View File

@ -1,6 +1,6 @@
import { FetcherError } from '@commerce/utils/errors' import { FetcherError } from '@commerce/utils/errors'
import type { GraphQLFetcher } from '@commerce/api' import type { GraphQLFetcher } from '@commerce/api'
import { getCommerceApi } from '../' import { getCommerceApi } from '../index'
import fetch from './fetch' import fetch from './fetch'
const fetchGraphqlApi: GraphQLFetcher = async ( const fetchGraphqlApi: GraphQLFetcher = async (
@ -25,7 +25,7 @@ const fetchGraphqlApi: GraphQLFetcher = async (
const json = await res.json() const json = await res.json()
if (json.errors) { if (json.errors) {
throw new FetcherError({ throw new FetcherError({
errors: json.errors ?? [{ message: 'Failed to fetch' }], errors: json.errors ?? [{ message: 'Failed to fetch for API' }],
status: res.status, status: res.status,
}) })
} }

View File

@ -9,8 +9,44 @@
"price": { "value": 25, "currencyCode": "USD" }, "price": { "value": 25, "currencyCode": "USD" },
"images": [ "images": [
{ {
"url": "/assets/drop-shirt-0", "url": "/assets/drop-shirt-0.png",
"altText": null, "altText": "Shirt",
"width": 1000,
"height": 1000
}
],
"variants": [],
"options": []
},
{
"id": "Z2lkOi8vc2hvcGlmeS9Qcm9kdWN0LzU0NDczMjUwMjQ0MjA=",
"name": "New Short Sleeve T-Shirt",
"vendor": "Next.js",
"path": "/new-short-sleeve-t-shirt",
"slug": "new-short-sleeve-t-shirt",
"price": { "value": 25, "currencyCode": "USD" },
"images": [
{
"url": "/assets/drop-shirt-0.png",
"altText": "Shirt",
"width": 1000,
"height": 1000
}
],
"variants": [],
"options": []
},
{
"id": "Z2lkOi8vc2hvcGlmeS9Qcm9kdWN0LzU0NDczMjUwMjQ0MjA=",
"name": "New Short Sleeve T-Shirt",
"vendor": "Next.js",
"path": "/new-short-sleeve-t-shirt",
"slug": "new-short-sleeve-t-shirt",
"price": { "value": 25, "currencyCode": "USD" },
"images": [
{
"url": "/assets/drop-shirt-0.png",
"altText": "Shirt",
"width": 1000, "width": 1000,
"height": 1000 "height": 1000
} }

View File

@ -1,16 +1,8 @@
import { Fetcher } from '@commerce/utils/types' import { Fetcher } from '@commerce/utils/types'
const shopApiUrl = '/data.json' export const fetcher: Fetcher = async () => {
console.log('FETCHER')
export const fetcher: Fetcher = async ({ const res = await fetch('./data.json')
url,
method = 'GET',
variables,
query,
body: bodyObj,
}) => {
const res = await fetch(shopApiUrl)
if (res.ok) { if (res.ok) {
const { data } = await res.json() const { data } = await res.json()
return data return data

View File

@ -1,13 +1,2 @@
import { useCallback } from 'react' export * from '@commerce/product/use-price'
export { default } from '@commerce/product/use-price'
export function emptyHook() {
const useEmptyHook = async (options = {}) => {
return useCallback(async function () {
return Promise.resolve()
}, [])
}
return useEmptyHook
}
export default emptyHook

View File

@ -1,4 +1,4 @@
import { Provider } from '@commerce' import { fetcher } from './fetcher'
import { handler as useCart } from './cart/use-cart' import { handler as useCart } from './cart/use-cart'
import { handler as useAddItem } from './cart/use-add-item' import { handler as useAddItem } from './cart/use-add-item'
import { handler as useUpdateItem } from './cart/use-update-item' import { handler as useUpdateItem } from './cart/use-update-item'
@ -8,11 +8,9 @@ import { handler as useSearch } from './product/use-search'
import { handler as useLogin } from './auth/use-login' import { handler as useLogin } from './auth/use-login'
import { handler as useLogout } from './auth/use-logout' import { handler as useLogout } from './auth/use-logout'
import { handler as useSignup } from './auth/use-signup' import { handler as useSignup } from './auth/use-signup'
import { fetcher } from './fetcher'
export type Provider = typeof localProvider export type Provider = typeof localProvider
export const localProvider = {
export const localProvider: Provider = {
locale: 'en-us', locale: 'en-us',
cartCookie: 'session', cartCookie: 'session',
fetcher: fetcher, fetcher: fetcher,

11033
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -29,6 +29,7 @@
"dot-object": "^2.1.4", "dot-object": "^2.1.4",
"email-validator": "^2.0.4", "email-validator": "^2.0.4",
"immutability-helper": "^3.1.1", "immutability-helper": "^3.1.1",
"isomorphic-unfetch": "^3.1.0",
"js-cookie": "^2.2.1", "js-cookie": "^2.2.1",
"keen-slider": "^5.4.1", "keen-slider": "^5.4.1",
"lodash.debounce": "^4.0.8", "lodash.debounce": "^4.0.8",

View File

@ -27,27 +27,5 @@
} }
}, },
"include": ["next-env.d.ts", "**/*.d.ts", "**/*.ts", "**/*.tsx", "**/*.js"], "include": ["next-env.d.ts", "**/*.d.ts", "**/*.ts", "**/*.tsx", "**/*.js"],
"exclude": [ "exclude": ["node_modules", "framework/swell", "framework/vendure"]
"node_modules",
"framework/swell",
"framework/vendure",
"components/cart",
"components/auth",
"components/wishlist",
"components/cart",
"components/auth",
"components/wishlist",
"components/cart",
"components/auth",
"components/wishlist",
"components/cart",
"components/auth",
"components/wishlist",
"components/cart",
"components/auth",
"components/wishlist",
"components/cart",
"components/auth",
"components/wishlist"
]
} }

View File

@ -3804,6 +3804,14 @@ isomorphic-form-data@2.0.0:
dependencies: dependencies:
form-data "^2.3.2" form-data "^2.3.2"
isomorphic-unfetch@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/isomorphic-unfetch/-/isomorphic-unfetch-3.1.0.tgz#87341d5f4f7b63843d468438128cb087b7c3e98f"
integrity sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q==
dependencies:
node-fetch "^2.6.1"
unfetch "^4.2.0"
isomorphic-ws@4.0.1: isomorphic-ws@4.0.1:
version "4.0.1" version "4.0.1"
resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz#55fd4cd6c5e6491e76dc125938dd863f5cd4f2dc" resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz#55fd4cd6c5e6491e76dc125938dd863f5cd4f2dc"
@ -6648,6 +6656,11 @@ unc-path-regex@^0.1.2:
resolved "https://registry.yarnpkg.com/unc-path-regex/-/unc-path-regex-0.1.2.tgz#e73dd3d7b0d7c5ed86fbac6b0ae7d8c6a69d50fa" resolved "https://registry.yarnpkg.com/unc-path-regex/-/unc-path-regex-0.1.2.tgz#e73dd3d7b0d7c5ed86fbac6b0ae7d8c6a69d50fa"
integrity sha1-5z3T17DXxe2G+6xrCufYxqadUPo= integrity sha1-5z3T17DXxe2G+6xrCufYxqadUPo=
unfetch@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/unfetch/-/unfetch-4.2.0.tgz#7e21b0ef7d363d8d9af0fb929a5555f6ef97a3be"
integrity sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==
uniq@^1.0.1: uniq@^1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff"