mirror of
https://github.com/vercel/commerce.git
synced 2025-03-14 14:42:31 +00:00
setup custom fetcher and auth hooks
This commit is contained in:
parent
753234dc51
commit
ee1d8ed461
@ -7,3 +7,6 @@ BIGCOMMERCE_CHANNEL_ID=
|
||||
|
||||
SHOPIFY_STORE_DOMAIN=
|
||||
SHOPIFY_STOREFRONT_ACCESS_TOKEN=
|
||||
|
||||
SWELL_STORE_ID=
|
||||
SWELL_PUBLIC_KEY=
|
15
.vscode/launch.json
vendored
Normal file
15
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "pwa-chrome",
|
||||
"request": "launch",
|
||||
"name": "Launch Chrome against localhost",
|
||||
"url": "http://localhost:8080",
|
||||
"webRoot": "${workspaceFolder}"
|
||||
}
|
||||
]
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"provider": "bigcommerce",
|
||||
"provider": "swell",
|
||||
"features": {
|
||||
"wishlist": true,
|
||||
"wishlist": false,
|
||||
"customCheckout": false
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
const merge = require('deepmerge')
|
||||
|
||||
const PROVIDERS = ['bigcommerce', 'shopify']
|
||||
const PROVIDERS = ['bigcommerce', 'shopify', 'swell']
|
||||
|
||||
function getProviderName() {
|
||||
return process.env.BIGCOMMERCE_STOREFRONT_API_URL ? 'bigcommerce' : null
|
||||
|
@ -1,2 +1,5 @@
|
||||
SHOPIFY_STORE_DOMAIN=
|
||||
SHOPIFY_STOREFRONT_ACCESS_TOKEN=
|
||||
|
||||
NEXT_PUBLIC_SWELL_STORE_ID=
|
||||
NEXT_PUBLIC_SWELL_PUBLIC_KEY=
|
||||
|
@ -22,23 +22,23 @@ if (!API_TOKEN) {
|
||||
|
||||
import fetchGraphqlApi from './utils/fetch-graphql-api'
|
||||
|
||||
export interface ShopifyConfig extends CommerceAPIConfig {}
|
||||
export interface SwellConfig extends CommerceAPIConfig {}
|
||||
|
||||
export class Config {
|
||||
private config: ShopifyConfig
|
||||
private config: SwellConfig
|
||||
|
||||
constructor(config: ShopifyConfig) {
|
||||
constructor(config: SwellConfig) {
|
||||
this.config = config
|
||||
}
|
||||
|
||||
getConfig(userConfig: Partial<ShopifyConfig> = {}) {
|
||||
return Object.entries(userConfig).reduce<ShopifyConfig>(
|
||||
getConfig(userConfig: Partial<SwellConfig> = {}) {
|
||||
return Object.entries(userConfig).reduce<SwellConfig>(
|
||||
(cfg, [key, value]) => Object.assign(cfg, { [key]: value }),
|
||||
{ ...this.config }
|
||||
)
|
||||
}
|
||||
|
||||
setConfig(newConfig: Partial<ShopifyConfig>) {
|
||||
setConfig(newConfig: Partial<SwellConfig>) {
|
||||
Object.assign(this.config, newConfig)
|
||||
}
|
||||
}
|
||||
@ -53,10 +53,10 @@ const config = new Config({
|
||||
customerCookie: SHOPIFY_CUSTOMER_TOKEN_COOKIE,
|
||||
})
|
||||
|
||||
export function getConfig(userConfig?: Partial<ShopifyConfig>) {
|
||||
export function getConfig(userConfig?: Partial<SwellConfig>) {
|
||||
return config.getConfig(userConfig)
|
||||
}
|
||||
|
||||
export function setConfig(newConfig: Partial<ShopifyConfig>) {
|
||||
export function setConfig(newConfig: Partial<SwellConfig>) {
|
||||
return config.setConfig(newConfig)
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
import Client from 'shopify-buy'
|
||||
import { ShopifyConfig } from '../index'
|
||||
import { SwellConfig } from '../index'
|
||||
|
||||
type Options = {
|
||||
config: ShopifyConfig
|
||||
config: SwellConfig
|
||||
}
|
||||
|
||||
const getAllCollections = async (options: Options) => {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Page } from '../../schema'
|
||||
import { ShopifyConfig, getConfig } from '..'
|
||||
import { SwellConfig, getConfig } from '..'
|
||||
|
||||
export type GetPageResult<T extends { page?: any } = { page?: Page }> = T
|
||||
|
||||
@ -15,7 +15,7 @@ async function getPage({
|
||||
}: {
|
||||
url?: string
|
||||
variables: PageVariables
|
||||
config?: ShopifyConfig
|
||||
config?: SwellConfig
|
||||
preview?: boolean
|
||||
}): Promise<GetPageResult> {
|
||||
config = getConfig(config)
|
||||
|
@ -1,5 +1,5 @@
|
||||
import type { NextApiHandler, NextApiRequest, NextApiResponse } from 'next'
|
||||
import { ShopifyConfig, getConfig } from '..'
|
||||
import { SwellConfig, getConfig } from '..'
|
||||
|
||||
export type ShopifyApiHandler<
|
||||
T = any,
|
||||
@ -8,7 +8,7 @@ export type ShopifyApiHandler<
|
||||
> = (
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse<ShopifyApiResponse<T>>,
|
||||
config: ShopifyConfig,
|
||||
config: SwellConfig,
|
||||
handlers: H,
|
||||
// Custom configs that may be used by a particular handler
|
||||
options: Options
|
||||
@ -17,7 +17,7 @@ export type ShopifyApiHandler<
|
||||
export type ShopifyHandler<T = any, Body = null> = (options: {
|
||||
req: NextApiRequest
|
||||
res: NextApiResponse<ShopifyApiResponse<T>>
|
||||
config: ShopifyConfig
|
||||
config: SwellConfig
|
||||
body: Body
|
||||
}) => void | Promise<void>
|
||||
|
||||
@ -44,7 +44,7 @@ export default function createApiHandler<
|
||||
operations,
|
||||
options,
|
||||
}: {
|
||||
config?: ShopifyConfig
|
||||
config?: SwellConfig
|
||||
operations?: Partial<H>
|
||||
options?: Options extends {} ? Partial<Options> : never
|
||||
} = {}): NextApiHandler {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { ProductEdge } from '../../schema'
|
||||
import { ShopifyConfig } from '..'
|
||||
import { SwellConfig } from '..'
|
||||
|
||||
const fetchAllProducts = async ({
|
||||
config,
|
||||
@ -8,7 +8,7 @@ const fetchAllProducts = async ({
|
||||
acc = [],
|
||||
cursor,
|
||||
}: {
|
||||
config: ShopifyConfig
|
||||
config: SwellConfig
|
||||
query: string
|
||||
acc?: ProductEdge[]
|
||||
variables?: any
|
||||
|
@ -25,7 +25,8 @@ const getErrorMessage = ({ code, message }: CustomerUserError) => {
|
||||
|
||||
export const handler: MutationHook<null, {}, CustomerAccessTokenCreateInput> = {
|
||||
fetchOptions: {
|
||||
query: createCustomerAccessTokenMutation,
|
||||
query: 'account',
|
||||
method: 'login',
|
||||
},
|
||||
async fetcher({ input: { email, password }, options, fetch }) {
|
||||
if (!(email && password)) {
|
||||
@ -40,9 +41,7 @@ export const handler: MutationHook<null, {}, CustomerAccessTokenCreateInput> = {
|
||||
MutationCheckoutCreateArgs
|
||||
>({
|
||||
...options,
|
||||
variables: {
|
||||
input: { email, password },
|
||||
},
|
||||
variables: [email, password],
|
||||
})
|
||||
|
||||
const errors = customerAccessTokenCreate?.customerUserErrors
|
||||
|
@ -9,7 +9,8 @@ export default useLogout as UseLogout<typeof handler>
|
||||
|
||||
export const handler: MutationHook<null> = {
|
||||
fetchOptions: {
|
||||
query: customerAccessTokenDeleteMutation,
|
||||
query: 'account',
|
||||
method: 'logout',
|
||||
},
|
||||
async fetcher({ options, fetch }) {
|
||||
await fetch({
|
||||
|
@ -20,7 +20,8 @@ export const handler: MutationHook<
|
||||
CustomerCreateInput
|
||||
> = {
|
||||
fetchOptions: {
|
||||
query: customerCreateMutation,
|
||||
query: 'account',
|
||||
method: 'create',
|
||||
},
|
||||
async fetcher({
|
||||
input: { firstName, lastName, email, password },
|
||||
@ -36,23 +37,20 @@ export const handler: MutationHook<
|
||||
const data = await fetch({
|
||||
...options,
|
||||
variables: {
|
||||
input: {
|
||||
firstName,
|
||||
lastName,
|
||||
email,
|
||||
password,
|
||||
},
|
||||
first_name: firstName,
|
||||
last_name: lastName,
|
||||
email,
|
||||
password,
|
||||
},
|
||||
})
|
||||
|
||||
try {
|
||||
const loginData = await fetch({
|
||||
query: customerAccessTokenCreateMutation,
|
||||
query: 'account',
|
||||
method: 'login',
|
||||
variables: {
|
||||
input: {
|
||||
email,
|
||||
password,
|
||||
},
|
||||
email,
|
||||
password,
|
||||
},
|
||||
})
|
||||
handleLogin(loginData)
|
||||
|
@ -18,7 +18,8 @@ export const handler: SWRHook<
|
||||
{ isEmpty?: boolean }
|
||||
> = {
|
||||
fetchOptions: {
|
||||
query: getCheckoutQuery,
|
||||
query: 'cart',
|
||||
method: 'get',
|
||||
},
|
||||
async fetcher({ input: { cartId: checkoutId }, options, fetch }) {
|
||||
let checkout
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"provider": "shopify",
|
||||
"provider": "swell",
|
||||
"features": {
|
||||
"wishlist": false
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { getConfig, ShopifyConfig } from '../api'
|
||||
import { getConfig, SwellConfig } from '../api'
|
||||
import { PageEdge } from '../schema'
|
||||
import { getAllPagesQuery } from '../utils/queries'
|
||||
|
||||
@ -20,7 +20,7 @@ export type Page = {
|
||||
|
||||
const getAllPages = async (options?: {
|
||||
variables?: Variables
|
||||
config: ShopifyConfig
|
||||
config: SwellConfig
|
||||
preview?: boolean
|
||||
}): Promise<ReturnType> => {
|
||||
let { config, variables = { first: 250 } } = options ?? {}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { getConfig, ShopifyConfig } from '../api'
|
||||
import { getConfig, SwellConfig } from '../api'
|
||||
import getPageQuery from '../utils/queries/get-page-query'
|
||||
import { Page } from './get-all-pages'
|
||||
|
||||
@ -10,7 +10,7 @@ export type GetPageResult<T extends { page?: any } = { page?: Page }> = T
|
||||
|
||||
const getPage = async (options: {
|
||||
variables: Variables
|
||||
config: ShopifyConfig
|
||||
config: SwellConfig
|
||||
preview?: boolean
|
||||
}): Promise<GetPageResult> => {
|
||||
let { config, variables } = options ?? {}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import getCategories, { Category } from '../utils/get-categories'
|
||||
import getVendors, { Brands } from '../utils/get-vendors'
|
||||
|
||||
import { getConfig, ShopifyConfig } from '../api'
|
||||
import { getConfig, SwellConfig } from '../api'
|
||||
|
||||
export type GetSiteInfoResult<
|
||||
T extends { categories: any[]; brands: any[] } = {
|
||||
@ -12,7 +12,7 @@ export type GetSiteInfoResult<
|
||||
|
||||
const getSiteInfo = async (options?: {
|
||||
variables?: any
|
||||
config: ShopifyConfig
|
||||
config: SwellConfig
|
||||
preview?: boolean
|
||||
}): Promise<GetSiteInfoResult> => {
|
||||
let { config } = options ?? {}
|
||||
|
@ -11,3 +11,7 @@ export const SHOPIFY_COOKIE_EXPIRE = 30
|
||||
export const API_URL = `https://${STORE_DOMAIN}/api/2021-01/graphql.json`
|
||||
|
||||
export const API_TOKEN = process.env.NEXT_PUBLIC_SHOPIFY_STOREFRONT_ACCESS_TOKEN
|
||||
|
||||
export const SWELL_STORE_ID = process.env.NEXT_PUBLIC_SWELL_STORE_ID
|
||||
|
||||
export const SWELL_PUBLIC_KEY = process.env.NEXT_PUBLIC_SWELL_PUBLIC_KEY
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { getConfig, ShopifyConfig } from '../api'
|
||||
import { getConfig, SwellConfig } from '../api'
|
||||
import getCustomerIdQuery from '../utils/queries/get-customer-id-query'
|
||||
import Cookies from 'js-cookie'
|
||||
|
||||
@ -7,7 +7,7 @@ async function getCustomerId({
|
||||
config,
|
||||
}: {
|
||||
customerToken: string
|
||||
config?: ShopifyConfig
|
||||
config?: SwellConfig
|
||||
}): Promise<number | undefined> {
|
||||
config = getConfig(config)
|
||||
|
||||
|
@ -1,20 +1,25 @@
|
||||
import useCustomer, { UseCustomer } from '@commerce/customer/use-customer'
|
||||
import { Customer } from '@commerce/types'
|
||||
import { SWRHook } from '@commerce/utils/types'
|
||||
import { getCustomerQuery, getCustomerToken } from '../utils'
|
||||
import { normalizeCustomer } from '../utils/normalize'
|
||||
// import { getCustomerQuery, getCustomerToken } from '../utils'
|
||||
|
||||
export default useCustomer as UseCustomer<typeof handler>
|
||||
|
||||
export const handler: SWRHook<Customer | null> = {
|
||||
fetchOptions: {
|
||||
query: getCustomerQuery,
|
||||
query: 'account',
|
||||
method: 'get',
|
||||
},
|
||||
async fetcher({ options, fetch }) {
|
||||
// console.log('STORE_ID', STORE_ID, 'PUBLIC_KEY', PUBLIC_KEY);
|
||||
// const data = await swell.account.get()
|
||||
const data = await fetch<any | null>({
|
||||
...options,
|
||||
variables: { customerAccessToken: getCustomerToken() },
|
||||
// variables: { customerAccessToken: getCustomerToken() },
|
||||
})
|
||||
return data.customer ?? null
|
||||
console.log(`Customer data ${data}`)
|
||||
return data ? normalizeCustomer(data) : null
|
||||
},
|
||||
useHook: ({ useData }) => (input) => {
|
||||
return useData({
|
||||
@ -25,3 +30,26 @@ export const handler: SWRHook<Customer | null> = {
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
// const handler = (): { data: Customer } => {
|
||||
// const swell = getContext();
|
||||
// const response = swell.account.get();
|
||||
// const { firstName, lastName, email, company, customerGroupId, notes, phone,
|
||||
// entityId, addressCount, attributeCount, storeCredit } = response;
|
||||
// return {
|
||||
// data: {
|
||||
// firstName,
|
||||
// lastName,
|
||||
// email,
|
||||
// company,
|
||||
// customerGroupId,
|
||||
// notes,
|
||||
// phone,
|
||||
// entityId,
|
||||
// addressCount,
|
||||
// attributeCount,
|
||||
// storeCredit
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// export default handler;
|
||||
|
@ -1,18 +1,25 @@
|
||||
import { Fetcher } from '@commerce/utils/types'
|
||||
import { API_TOKEN, API_URL } from './const'
|
||||
import { handleFetchResponse } from './utils'
|
||||
import { swellConfig } from './index'
|
||||
|
||||
const fetcher: Fetcher = async ({ method = 'POST', variables, query }) => {
|
||||
return handleFetchResponse(
|
||||
await fetch(API_URL, {
|
||||
method,
|
||||
body: JSON.stringify({ query, variables }),
|
||||
headers: {
|
||||
'X-Shopify-Storefront-Access-Token': API_TOKEN!,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
})
|
||||
)
|
||||
const fetcher: Fetcher = async ({ method = 'get', variables, query }) => {
|
||||
const { swell } = swellConfig
|
||||
async function callSwell() {
|
||||
if (Array.isArray(variables)) {
|
||||
const arg1 = variables[0]
|
||||
const arg2 = variables[1]
|
||||
const response = await swell[query][method](arg1, arg2)
|
||||
console.log(response)
|
||||
return handleFetchResponse(response)
|
||||
} else {
|
||||
const response = await swell[query][method](variables)
|
||||
console.log(response)
|
||||
return handleFetchResponse(response)
|
||||
}
|
||||
}
|
||||
if (query) {
|
||||
return await callSwell()
|
||||
}
|
||||
}
|
||||
|
||||
export default fetcher
|
||||
|
@ -1,4 +1,5 @@
|
||||
import * as React from 'react'
|
||||
import swell from 'swell-js'
|
||||
import { ReactNode } from 'react'
|
||||
|
||||
import {
|
||||
@ -7,30 +8,36 @@ import {
|
||||
useCommerce as useCoreCommerce,
|
||||
} from '@commerce'
|
||||
|
||||
import { shopifyProvider, ShopifyProvider } from './provider'
|
||||
import { SHOPIFY_CHECKOUT_ID_COOKIE } from './const'
|
||||
import { swellProvider, SwellProvider } from './provider'
|
||||
import {
|
||||
SHOPIFY_CHECKOUT_ID_COOKIE,
|
||||
SWELL_STORE_ID,
|
||||
SWELL_PUBLIC_KEY,
|
||||
} from './const'
|
||||
swell.init(SWELL_STORE_ID, SWELL_PUBLIC_KEY)
|
||||
|
||||
export { shopifyProvider }
|
||||
export type { ShopifyProvider }
|
||||
export { swellProvider }
|
||||
export type { SwellProvider }
|
||||
|
||||
export const shopifyConfig: CommerceConfig = {
|
||||
export const swellConfig: any = {
|
||||
locale: 'en-us',
|
||||
cartCookie: SHOPIFY_CHECKOUT_ID_COOKIE,
|
||||
swell,
|
||||
}
|
||||
|
||||
export type ShopifyConfig = Partial<CommerceConfig>
|
||||
export type SwellConfig = Partial<CommerceConfig>
|
||||
|
||||
export type ShopifyProps = {
|
||||
export type SwellProps = {
|
||||
children?: ReactNode
|
||||
locale: string
|
||||
} & ShopifyConfig
|
||||
} & SwellConfig
|
||||
|
||||
export function CommerceProvider({ children, ...config }: ShopifyProps) {
|
||||
export function CommerceProvider({ children, ...config }: SwellProps) {
|
||||
return (
|
||||
<CoreCommerceProvider
|
||||
// TODO: Fix this type
|
||||
provider={shopifyProvider as any}
|
||||
config={{ ...shopifyConfig, ...config }}
|
||||
provider={swellProvider as any}
|
||||
config={{ ...swellConfig, ...config }}
|
||||
>
|
||||
{children}
|
||||
</CoreCommerceProvider>
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { CollectionEdge } from '../schema'
|
||||
import { getConfig, ShopifyConfig } from '../api'
|
||||
import { getConfig, SwellConfig } from '../api'
|
||||
import getAllCollectionsQuery from '../utils/queries/get-all-collections-query'
|
||||
|
||||
const getAllCollections = async (options?: {
|
||||
variables?: any
|
||||
config: ShopifyConfig
|
||||
config: SwellConfig
|
||||
preview?: boolean
|
||||
}) => {
|
||||
let { config, variables = { first: 250 } } = options ?? {}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Product } from '@commerce/types'
|
||||
import { getConfig, ShopifyConfig } from '../api'
|
||||
import { getConfig, SwellConfig } from '../api'
|
||||
import fetchAllProducts from '../api/utils/fetch-all-products'
|
||||
import { ProductEdge } from '../schema'
|
||||
import getAllProductsPathsQuery from '../utils/queries/get-all-products-paths-query'
|
||||
@ -18,7 +18,7 @@ type ReturnType = {
|
||||
|
||||
const getAllProductPaths = async (options?: {
|
||||
variables?: any
|
||||
config?: ShopifyConfig
|
||||
config?: SwellConfig
|
||||
preview?: boolean
|
||||
}): Promise<ReturnType> => {
|
||||
let { config, variables = { first: 250 } } = options ?? {}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { GraphQLFetcherResult } from '@commerce/api'
|
||||
import { getConfig, ShopifyConfig } from '../api'
|
||||
import { getConfig, SwellConfig } from '../api'
|
||||
import { ProductEdge } from '../schema'
|
||||
import { getAllProductsQuery } from '../utils/queries'
|
||||
import { normalizeProduct } from '../utils/normalize'
|
||||
@ -16,7 +16,7 @@ type ReturnType = {
|
||||
|
||||
const getAllProducts = async (options: {
|
||||
variables?: Variables
|
||||
config?: ShopifyConfig
|
||||
config?: SwellConfig
|
||||
preview?: boolean
|
||||
}): Promise<ReturnType> => {
|
||||
let { config, variables = { first: 250 } } = options ?? {}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { GraphQLFetcherResult } from '@commerce/api'
|
||||
import { getConfig, ShopifyConfig } from '../api'
|
||||
import { getConfig, SwellConfig } from '../api'
|
||||
import { normalizeProduct, getProductQuery } from '../utils'
|
||||
|
||||
type Variables = {
|
||||
@ -12,7 +12,7 @@ type ReturnType = {
|
||||
|
||||
const getProduct = async (options: {
|
||||
variables: Variables
|
||||
config: ShopifyConfig
|
||||
config: SwellConfig
|
||||
preview?: boolean
|
||||
}): Promise<ReturnType> => {
|
||||
let { config, variables } = options ?? {}
|
||||
|
@ -14,7 +14,7 @@ import { handler as useSignup } from './auth/use-signup'
|
||||
|
||||
import fetcher from './fetcher'
|
||||
|
||||
export const shopifyProvider = {
|
||||
export const swellProvider = {
|
||||
locale: 'en-us',
|
||||
cartCookie: SHOPIFY_CHECKOUT_ID_COOKIE,
|
||||
storeDomain: STORE_DOMAIN,
|
||||
@ -28,4 +28,4 @@ export const shopifyProvider = {
|
||||
},
|
||||
}
|
||||
|
||||
export type ShopifyProvider = typeof shopifyProvider
|
||||
export type SwellProvider = typeof swellProvider
|
||||
|
1
framework/swell/swell-js.d.ts
vendored
Normal file
1
framework/swell/swell-js.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
||||
declare module 'swell-js'
|
@ -1,6 +1,11 @@
|
||||
import * as Core from '@commerce/types'
|
||||
import { CheckoutLineItem } from './schema'
|
||||
|
||||
export interface SwellCustomer extends Core.Customer {
|
||||
first_name: string
|
||||
last_name: string
|
||||
}
|
||||
|
||||
export type ShopifyCheckout = {
|
||||
id: string
|
||||
webUrl: string
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { ShopifyConfig } from '../api'
|
||||
import { SwellConfig } from '../api'
|
||||
import { CollectionEdge } from '../schema'
|
||||
import getSiteCollectionsQuery from './queries/get-all-collections-query'
|
||||
|
||||
@ -8,7 +8,7 @@ export type Category = {
|
||||
path: string
|
||||
}
|
||||
|
||||
const getCategories = async (config: ShopifyConfig): Promise<Category[]> => {
|
||||
const getCategories = async (config: SwellConfig): Promise<Category[]> => {
|
||||
const { data } = await config.fetch(getSiteCollectionsQuery, {
|
||||
variables: {
|
||||
first: 250,
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { ShopifyConfig } from '../api'
|
||||
import { SwellConfig } from '../api'
|
||||
import fetchAllProducts from '../api/utils/fetch-all-products'
|
||||
import getAllProductVendors from './queries/get-all-product-vendors-query'
|
||||
|
||||
@ -13,7 +13,7 @@ export type BrandEdge = {
|
||||
|
||||
export type Brands = BrandEdge[]
|
||||
|
||||
const getVendors = async (config: ShopifyConfig): Promise<BrandEdge[]> => {
|
||||
const getVendors = async (config: SwellConfig): Promise<BrandEdge[]> => {
|
||||
const vendors = await fetchAllProducts({
|
||||
config,
|
||||
query: getAllProductVendors,
|
||||
|
@ -11,15 +11,16 @@ export async function getAsyncError(res: Response) {
|
||||
}
|
||||
|
||||
const handleFetchResponse = async (res: Response) => {
|
||||
if (res.ok) {
|
||||
const { data, errors } = await res.json()
|
||||
// if (res.ok) {
|
||||
// const { data, errors } = await res.json()
|
||||
|
||||
if (errors && errors.length) {
|
||||
throw getError(errors, res.status)
|
||||
}
|
||||
// if (errors && errors.length) {
|
||||
// throw getError(errors, res.status)
|
||||
// }
|
||||
|
||||
return data
|
||||
}
|
||||
// return data
|
||||
// }
|
||||
if (res) return res
|
||||
|
||||
throw await getAsyncError(res)
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { Product } from '@commerce/types'
|
||||
import { Customer } from '@commerce/types'
|
||||
|
||||
import {
|
||||
Product as ShopifyProduct,
|
||||
@ -11,7 +12,7 @@ import {
|
||||
ProductOption,
|
||||
} from '../schema'
|
||||
|
||||
import type { Cart, LineItem } from '../types'
|
||||
import type { Cart, LineItem, SwellCustomer } from '../types'
|
||||
|
||||
const money = ({ amount, currencyCode }: MoneyV2) => {
|
||||
return {
|
||||
@ -121,6 +122,15 @@ export function normalizeCart(checkout: Checkout): Cart {
|
||||
}
|
||||
}
|
||||
|
||||
export function normalizeCustomer(customer: SwellCustomer): Customer {
|
||||
const { first_name: firstName, last_name: lastName } = customer
|
||||
return {
|
||||
...customer,
|
||||
firstName,
|
||||
lastName,
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeLineItem({
|
||||
node: { id, title, variant, quantity },
|
||||
}: CheckoutLineItemEdge): LineItem {
|
||||
|
@ -42,6 +42,7 @@
|
||||
"react-merge-refs": "^1.1.0",
|
||||
"react-ticker": "^1.2.2",
|
||||
"shopify-buy": "^2.11.0",
|
||||
"swell-js": "^4.0.0-next.0",
|
||||
"swr": "^0.4.0",
|
||||
"tabbable": "^5.1.5",
|
||||
"tailwindcss": "^2.0.3"
|
||||
|
@ -22,10 +22,10 @@
|
||||
"@components/*": ["components/*"],
|
||||
"@commerce": ["framework/commerce"],
|
||||
"@commerce/*": ["framework/commerce/*"],
|
||||
"@framework": ["framework/bigcommerce"],
|
||||
"@framework/*": ["framework/bigcommerce/*"]
|
||||
"@framework": ["framework/swell"],
|
||||
"@framework/*": ["framework/swell/*"]
|
||||
}
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.d.ts", "**/*.ts", "**/*.tsx", "**/*.js"],
|
||||
"exclude": ["node_modules"]
|
||||
"exclude": ["node_modules", "swell-js"]
|
||||
}
|
||||
|
118
yarn.lock
118
yarn.lock
@ -401,6 +401,13 @@
|
||||
dependencies:
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@babel/runtime@7.4.5":
|
||||
version "7.4.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.4.5.tgz#582bb531f5f9dc67d2fcb682979894f75e253f12"
|
||||
integrity sha512-TuI4qpWZP6lGOGIuGWtp9sPluqYICmbk8T/1vpSysqJxRPkudh/ofFWyqdcMsDf2s7KvDL4/YHgKyvcS3g9CJQ==
|
||||
dependencies:
|
||||
regenerator-runtime "^0.13.2"
|
||||
|
||||
"@babel/runtime@^7.0.0":
|
||||
version "7.12.13"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.13.tgz#0a21452352b02542db0ffb928ac2d3ca7cb6d66d"
|
||||
@ -408,6 +415,13 @@
|
||||
dependencies:
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@babel/runtime@^7.12.13", "@babel/runtime@^7.13.10":
|
||||
version "7.13.10"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.13.10.tgz#47d42a57b6095f4468da440388fdbad8bebf0d7d"
|
||||
integrity sha512-4QPkjJq6Ns3V/RgpEahRk+AGfL0eO6RHHtTWoNNr5mO49G6B5+X6d6THgWEAvTrznU5xYpbAlVKRYcsCgh/Akw==
|
||||
dependencies:
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@babel/template@^7.12.13":
|
||||
version "7.12.13"
|
||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.12.13.tgz#530265be8a2589dbb37523844c5bcb55947fb327"
|
||||
@ -1522,6 +1536,14 @@ array-flatten@^3.0.0:
|
||||
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-3.0.0.tgz#6428ca2ee52c7b823192ec600fa3ed2f157cd541"
|
||||
integrity sha512-zPMVc3ZYlGLNk4mpK1NzP2wg0ml9t7fUgDsayR5Y5rSzxQilzR9FGu/EH2jQOcKSAeAfWeylyW8juy3OkWRvNA==
|
||||
|
||||
array-includes-with-glob@^3.0.6:
|
||||
version "3.0.8"
|
||||
resolved "https://registry.yarnpkg.com/array-includes-with-glob/-/array-includes-with-glob-3.0.8.tgz#522a982e7913a9e6397efd3d933aa3cc61776cb2"
|
||||
integrity sha512-g1XH4sJ/LMdyUSDB/9pNEC/eEO62chSTIi9I5agGHi4NI90SASER1Qe4emrTgCeaNPCAcivfi3Ba0owq6Pwo4Q==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
matcher "^4.0.0"
|
||||
|
||||
array-union@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d"
|
||||
@ -2542,7 +2564,7 @@ deep-is@~0.1.3:
|
||||
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
|
||||
integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=
|
||||
|
||||
deepmerge@^4.2.2:
|
||||
deepmerge@4.2.2, deepmerge@^4.2.2:
|
||||
version "4.2.2"
|
||||
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955"
|
||||
integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==
|
||||
@ -2914,6 +2936,11 @@ escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
|
||||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
|
||||
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
|
||||
|
||||
escape-string-regexp@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
|
||||
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
|
||||
|
||||
escodegen@^1.8.0:
|
||||
version "1.14.3"
|
||||
resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503"
|
||||
@ -3896,7 +3923,7 @@ isobject@^4.0.0:
|
||||
resolved "https://registry.yarnpkg.com/isobject/-/isobject-4.0.0.tgz#3f1c9155e73b192022a80819bacd0343711697b0"
|
||||
integrity sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA==
|
||||
|
||||
isomorphic-fetch@^3.0.0:
|
||||
isomorphic-fetch@3.0.0, isomorphic-fetch@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz#0267b005049046d2421207215d45d6a262b8b8b4"
|
||||
integrity sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==
|
||||
@ -4219,6 +4246,16 @@ lodash._reinterpolate@^3.0.0:
|
||||
resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d"
|
||||
integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=
|
||||
|
||||
lodash.camelcase@^4.3.0:
|
||||
version "4.3.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
|
||||
integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY=
|
||||
|
||||
lodash.clonedeep@^4.5.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
|
||||
integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=
|
||||
|
||||
lodash.debounce@^4.0.8:
|
||||
version "4.0.8"
|
||||
resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
|
||||
@ -4239,6 +4276,11 @@ lodash.isboolean@^3.0.3:
|
||||
resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6"
|
||||
integrity sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=
|
||||
|
||||
lodash.isdate@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/lodash.isdate/-/lodash.isdate-4.0.1.tgz#35a543673b9d76110de4114b32cc577048a7f366"
|
||||
integrity sha1-NaVDZzuddhEN5BFLMsxXcEin82Y=
|
||||
|
||||
lodash.isinteger@^4.0.4:
|
||||
version "4.0.4"
|
||||
resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343"
|
||||
@ -4269,6 +4311,11 @@ lodash.random@^3.2.0:
|
||||
resolved "https://registry.yarnpkg.com/lodash.random/-/lodash.random-3.2.0.tgz#96e24e763333199130d2c9e2fd57f91703cc262d"
|
||||
integrity sha1-luJOdjMzGZEw0sni/Vf5FwPMJi0=
|
||||
|
||||
lodash.snakecase@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz#39d714a35357147837aefd64b5dcbb16becd8f8d"
|
||||
integrity sha1-OdcUo1NXFHg3rv1ktdy7Fr7Nj40=
|
||||
|
||||
lodash.sortby@^4.7.0:
|
||||
version "4.7.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
|
||||
@ -4299,6 +4346,16 @@ lodash.toarray@^4.4.0:
|
||||
resolved "https://registry.yarnpkg.com/lodash.toarray/-/lodash.toarray-4.4.0.tgz#24c4bfcd6b2fba38bfd0594db1179d8e9b656561"
|
||||
integrity sha1-JMS/zWsvuji/0FlNsRedjptlZWE=
|
||||
|
||||
lodash.uniq@^4.5.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
|
||||
integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
|
||||
|
||||
lodash@4.17.21:
|
||||
version "4.17.21"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
|
||||
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
|
||||
|
||||
lodash@^4.17.13, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@~4.17.20:
|
||||
version "4.17.20"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
|
||||
@ -4445,6 +4502,13 @@ map-obj@^4.0.0:
|
||||
resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.1.0.tgz#b91221b542734b9f14256c0132c897c5d7256fd5"
|
||||
integrity sha512-glc9y00wgtwcDmp7GaE/0b0OnxpNJsVf3ael/An6Fe2Q51LLwN1er6sdomLRzz5h0+yMpiYLhWYF5R7HeqVd4g==
|
||||
|
||||
matcher@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/matcher/-/matcher-4.0.0.tgz#a42a05a09aaed92e2d241eb91fddac689461ea51"
|
||||
integrity sha512-S6x5wmcDmsDRRU/c2dkccDwQPXoFczc5+HpQ2lON8pnvHlnvHAHj5WlLVvw6n6vNyHuVugYrFohYxbS+pvFpKQ==
|
||||
dependencies:
|
||||
escape-string-regexp "^4.0.0"
|
||||
|
||||
md5.js@^1.3.4:
|
||||
version "1.3.5"
|
||||
resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f"
|
||||
@ -4891,11 +4955,33 @@ object-inspect@^1.9.0:
|
||||
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.9.0.tgz#c90521d74e1127b67266ded3394ad6116986533a"
|
||||
integrity sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==
|
||||
|
||||
object-keys-normalizer@1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/object-keys-normalizer/-/object-keys-normalizer-1.0.1.tgz#db178dbba5e4c7b18b40837c8ef83365ee9348e7"
|
||||
integrity sha1-2xeNu6Xkx7GLQIN8jvgzZe6TSOc=
|
||||
dependencies:
|
||||
lodash.camelcase "^4.3.0"
|
||||
lodash.snakecase "^4.1.1"
|
||||
|
||||
object-keys@^1.0.12, object-keys@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
|
||||
integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
|
||||
|
||||
object-merge-advanced@12.0.3:
|
||||
version "12.0.3"
|
||||
resolved "https://registry.yarnpkg.com/object-merge-advanced/-/object-merge-advanced-12.0.3.tgz#e03c19aa33cf88da6b32187e4907b487668808d9"
|
||||
integrity sha512-xQIf2Vup1rpKiHr2tQca5jyNYgT4O0kNxOfAp3ZNonm2hS+5yaJgI0Czdk/QMy52bcRwQKX3uc3H8XtAiiYfVA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.12.13"
|
||||
array-includes-with-glob "^3.0.6"
|
||||
lodash.clonedeep "^4.5.0"
|
||||
lodash.includes "^4.3.0"
|
||||
lodash.isdate "^4.0.1"
|
||||
lodash.isplainobject "^4.0.6"
|
||||
lodash.uniq "^4.5.0"
|
||||
util-nonempty "^3.0.6"
|
||||
|
||||
object-path@^0.11.4:
|
||||
version "0.11.5"
|
||||
resolved "https://registry.yarnpkg.com/object-path/-/object-path-0.11.5.tgz#d4e3cf19601a5140a55a16ad712019a9c50b577a"
|
||||
@ -5755,6 +5841,11 @@ purgecss@^3.1.3:
|
||||
postcss "^8.2.1"
|
||||
postcss-selector-parser "^6.0.2"
|
||||
|
||||
qs@6.7.0:
|
||||
version "6.7.0"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
|
||||
integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==
|
||||
|
||||
querystring-es3@^0.2.0:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73"
|
||||
@ -5916,7 +6007,7 @@ reduce-css-calc@^2.1.8:
|
||||
css-unit-converter "^1.1.1"
|
||||
postcss-value-parser "^3.3.0"
|
||||
|
||||
regenerator-runtime@^0.13.4:
|
||||
regenerator-runtime@^0.13.2, regenerator-runtime@^0.13.4:
|
||||
version "0.13.7"
|
||||
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55"
|
||||
integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==
|
||||
@ -6609,6 +6700,19 @@ supports-color@^7.0.0, supports-color@^7.1.0:
|
||||
dependencies:
|
||||
has-flag "^4.0.0"
|
||||
|
||||
swell-js@^4.0.0-next.0:
|
||||
version "4.0.0-next.0"
|
||||
resolved "https://registry.yarnpkg.com/swell-js/-/swell-js-4.0.0-next.0.tgz#870599372e3c9eafefeafc2c63863c4032d8be6b"
|
||||
integrity sha512-OQ1FLft3ruKpQw5P0TiCzs/X2Ma95+Qz+I2Xzs4KC6v+zVaFVUGNs80dQdtjfInisWoFC7iFZF2AITgellVGAg==
|
||||
dependencies:
|
||||
"@babel/runtime" "7.4.5"
|
||||
deepmerge "4.2.2"
|
||||
isomorphic-fetch "3.0.0"
|
||||
lodash "4.17.21"
|
||||
object-keys-normalizer "1.0.1"
|
||||
object-merge-advanced "12.0.3"
|
||||
qs "6.7.0"
|
||||
|
||||
swr@^0.4.0:
|
||||
version "0.4.2"
|
||||
resolved "https://registry.yarnpkg.com/swr/-/swr-0.4.2.tgz#4a9ed5e9948088af145c79d716d294cb99712a29"
|
||||
@ -6982,6 +7086,14 @@ util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
||||
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
|
||||
|
||||
util-nonempty@^3.0.6:
|
||||
version "3.0.8"
|
||||
resolved "https://registry.yarnpkg.com/util-nonempty/-/util-nonempty-3.0.8.tgz#0e53820a29e2c6cdcc3ecece52bc7fdd193c9b2b"
|
||||
integrity sha512-eB6dfVQWEBMT7i9EgWigvJiHUlW/iaq/Wg6pcWviwKsPWFwgprPVilZHkTAhzmXgv9LnGOLjrszm/HvIHpbeQw==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
lodash.isplainobject "^4.0.6"
|
||||
|
||||
util@0.10.3:
|
||||
version "0.10.3"
|
||||
resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9"
|
||||
|
Loading…
x
Reference in New Issue
Block a user