From 66e3269b0e804883ea024bc98668367ddf2acfa1 Mon Sep 17 00:00:00 2001 From: Dom Sip Date: Wed, 20 Apr 2022 18:08:26 +0100 Subject: [PATCH] SFCC provider (#727) * new SFCC provider * add search * normalization + search * categories as search results * adress PR feedback * Update README.md * get all paths for SSG * product variants and options * Apply suggestions from code review Co-authored-by: Luis Alvarez D. * remove console log * prettier * clean console log * ran prettier * Updated readme * remove static data and revert config changes * set default site Co-authored-by: Luis Alvarez D. --- packages/commerce/new-provider.md | 1 + packages/sfcc/.env.template | 7 + packages/sfcc/.prettierignore | 2 + packages/sfcc/.prettierrc | 6 + packages/sfcc/README.md | 38 ++ packages/sfcc/package.json | 80 ++++ packages/sfcc/src/api/endpoints/cart/index.ts | 1 + .../catalog/products/get-products.ts | 32 ++ .../api/endpoints/catalog/products/index.ts | 19 + .../sfcc/src/api/endpoints/checkout/index.ts | 1 + .../src/api/endpoints/customer/address.ts | 1 + .../sfcc/src/api/endpoints/customer/card.ts | 1 + .../sfcc/src/api/endpoints/customer/index.ts | 1 + .../sfcc/src/api/endpoints/login/index.ts | 1 + .../sfcc/src/api/endpoints/logout/index.ts | 1 + .../sfcc/src/api/endpoints/signup/index.ts | 1 + .../sfcc/src/api/endpoints/wishlist/index.tsx | 1 + packages/sfcc/src/api/index.ts | 48 ++ .../sfcc/src/api/operations/get-all-pages.ts | 19 + .../api/operations/get-all-product-paths.ts | 45 ++ .../src/api/operations/get-all-products.ts | 40 ++ .../api/operations/get-customer-wishlist.ts | 6 + packages/sfcc/src/api/operations/get-page.ts | 13 + .../sfcc/src/api/operations/get-product.ts | 33 ++ .../sfcc/src/api/operations/get-site-info.ts | 43 ++ packages/sfcc/src/api/operations/index.ts | 6 + packages/sfcc/src/api/utils/fetch-local.ts | 34 ++ packages/sfcc/src/api/utils/fetch.ts | 3 + packages/sfcc/src/api/utils/get-auth-token.ts | 42 ++ .../sfcc/src/api/utils/normalise-product.ts | 96 ++++ packages/sfcc/src/api/utils/sfcc-sdk.ts | 19 + packages/sfcc/src/auth/index.ts | 3 + packages/sfcc/src/auth/use-login.tsx | 16 + packages/sfcc/src/auth/use-logout.tsx | 17 + packages/sfcc/src/auth/use-signup.tsx | 19 + packages/sfcc/src/cart/index.ts | 4 + packages/sfcc/src/cart/use-add-item.tsx | 17 + packages/sfcc/src/cart/use-cart.tsx | 42 ++ packages/sfcc/src/cart/use-remove-item.tsx | 20 + packages/sfcc/src/cart/use-update-item.tsx | 20 + packages/sfcc/src/checkout/use-checkout.tsx | 16 + packages/sfcc/src/commerce.config.json | 10 + .../src/customer/address/use-add-item.tsx | 17 + .../sfcc/src/customer/card/use-add-item.tsx | 17 + packages/sfcc/src/customer/index.ts | 1 + packages/sfcc/src/customer/use-customer.tsx | 17 + packages/sfcc/src/fetcher.ts | 17 + packages/sfcc/src/index.tsx | 12 + packages/sfcc/src/next.config.cjs | 12 + packages/sfcc/src/product/index.ts | 2 + packages/sfcc/src/product/use-price.tsx | 2 + packages/sfcc/src/product/use-search.tsx | 42 ++ packages/sfcc/src/provider.ts | 22 + packages/sfcc/src/wishlist/use-add-item.tsx | 13 + .../sfcc/src/wishlist/use-remove-item.tsx | 17 + packages/sfcc/src/wishlist/use-wishlist.tsx | 43 ++ packages/sfcc/taskfile.js | 20 + packages/sfcc/tsconfig.json | 21 + site/.env.template | 7 + site/commerce-config.js | 1 + yarn.lock | 419 +++++++++++++++++- 61 files changed, 1516 insertions(+), 11 deletions(-) create mode 100644 packages/sfcc/.env.template create mode 100644 packages/sfcc/.prettierignore create mode 100644 packages/sfcc/.prettierrc create mode 100644 packages/sfcc/README.md create mode 100644 packages/sfcc/package.json create mode 100644 packages/sfcc/src/api/endpoints/cart/index.ts create mode 100644 packages/sfcc/src/api/endpoints/catalog/products/get-products.ts create mode 100644 packages/sfcc/src/api/endpoints/catalog/products/index.ts create mode 100644 packages/sfcc/src/api/endpoints/checkout/index.ts create mode 100644 packages/sfcc/src/api/endpoints/customer/address.ts create mode 100644 packages/sfcc/src/api/endpoints/customer/card.ts create mode 100644 packages/sfcc/src/api/endpoints/customer/index.ts create mode 100644 packages/sfcc/src/api/endpoints/login/index.ts create mode 100644 packages/sfcc/src/api/endpoints/logout/index.ts create mode 100644 packages/sfcc/src/api/endpoints/signup/index.ts create mode 100644 packages/sfcc/src/api/endpoints/wishlist/index.tsx create mode 100644 packages/sfcc/src/api/index.ts create mode 100644 packages/sfcc/src/api/operations/get-all-pages.ts create mode 100644 packages/sfcc/src/api/operations/get-all-product-paths.ts create mode 100644 packages/sfcc/src/api/operations/get-all-products.ts create mode 100644 packages/sfcc/src/api/operations/get-customer-wishlist.ts create mode 100644 packages/sfcc/src/api/operations/get-page.ts create mode 100644 packages/sfcc/src/api/operations/get-product.ts create mode 100644 packages/sfcc/src/api/operations/get-site-info.ts create mode 100644 packages/sfcc/src/api/operations/index.ts create mode 100644 packages/sfcc/src/api/utils/fetch-local.ts create mode 100644 packages/sfcc/src/api/utils/fetch.ts create mode 100644 packages/sfcc/src/api/utils/get-auth-token.ts create mode 100644 packages/sfcc/src/api/utils/normalise-product.ts create mode 100644 packages/sfcc/src/api/utils/sfcc-sdk.ts create mode 100644 packages/sfcc/src/auth/index.ts create mode 100644 packages/sfcc/src/auth/use-login.tsx create mode 100644 packages/sfcc/src/auth/use-logout.tsx create mode 100644 packages/sfcc/src/auth/use-signup.tsx create mode 100644 packages/sfcc/src/cart/index.ts create mode 100644 packages/sfcc/src/cart/use-add-item.tsx create mode 100644 packages/sfcc/src/cart/use-cart.tsx create mode 100644 packages/sfcc/src/cart/use-remove-item.tsx create mode 100644 packages/sfcc/src/cart/use-update-item.tsx create mode 100644 packages/sfcc/src/checkout/use-checkout.tsx create mode 100644 packages/sfcc/src/commerce.config.json create mode 100644 packages/sfcc/src/customer/address/use-add-item.tsx create mode 100644 packages/sfcc/src/customer/card/use-add-item.tsx create mode 100644 packages/sfcc/src/customer/index.ts create mode 100644 packages/sfcc/src/customer/use-customer.tsx create mode 100644 packages/sfcc/src/fetcher.ts create mode 100644 packages/sfcc/src/index.tsx create mode 100644 packages/sfcc/src/next.config.cjs create mode 100644 packages/sfcc/src/product/index.ts create mode 100644 packages/sfcc/src/product/use-price.tsx create mode 100644 packages/sfcc/src/product/use-search.tsx create mode 100644 packages/sfcc/src/provider.ts create mode 100644 packages/sfcc/src/wishlist/use-add-item.tsx create mode 100644 packages/sfcc/src/wishlist/use-remove-item.tsx create mode 100644 packages/sfcc/src/wishlist/use-wishlist.tsx create mode 100644 packages/sfcc/taskfile.js create mode 100644 packages/sfcc/tsconfig.json diff --git a/packages/commerce/new-provider.md b/packages/commerce/new-provider.md index 546b933f6..c75076175 100644 --- a/packages/commerce/new-provider.md +++ b/packages/commerce/new-provider.md @@ -14,6 +14,7 @@ A commerce provider is a headless e-commerce platform that integrates with the [ - Spree ([packages/spree](../spree)) - Kibo Commerce ([packages/kibocommerce](../kibocommerce)) - Commerce.js ([packages/commercejs](../commercejs)) +- SFCC - SalesForce Cloud Commerce ([packages/sfcc](../sfcc)) Adding a commerce provider means adding a new folder in `packages` with a folder structure like the next one: diff --git a/packages/sfcc/.env.template b/packages/sfcc/.env.template new file mode 100644 index 000000000..a649427b2 --- /dev/null +++ b/packages/sfcc/.env.template @@ -0,0 +1,7 @@ +COMMERCE_PROVIDER=@vercel/commerce-sfcc + +SFCC_CLIENT_ID= +SFCC_CLIENT_SECRET= +SFCC_ORG_ID= +SFCC_SHORT_CODE= +SFCC_SITE_ID= \ No newline at end of file diff --git a/packages/sfcc/.prettierignore b/packages/sfcc/.prettierignore new file mode 100644 index 000000000..f06235c46 --- /dev/null +++ b/packages/sfcc/.prettierignore @@ -0,0 +1,2 @@ +node_modules +dist diff --git a/packages/sfcc/.prettierrc b/packages/sfcc/.prettierrc new file mode 100644 index 000000000..e1076edfa --- /dev/null +++ b/packages/sfcc/.prettierrc @@ -0,0 +1,6 @@ +{ + "semi": false, + "singleQuote": true, + "tabWidth": 2, + "useTabs": false +} diff --git a/packages/sfcc/README.md b/packages/sfcc/README.md new file mode 100644 index 000000000..21b2bd613 --- /dev/null +++ b/packages/sfcc/README.md @@ -0,0 +1,38 @@ +# Next.js SalesForce Cloud Commerce Provider + +## Installation + +1. Copy the `.env.template` file in this directory to `/site/.env.local` in the main directory +2. Run `yarn` and then `yarn dev` in root folder + +## Features: + +```json +{ + "provider": "sfcc", + "features": { + "wishlist": false, + "cart": false, + "search": true, + "customerAuth": false, + "customCheckout": false + } +} +``` + +## References + +- SDK: https://github.com/SalesforceCommerceCloud/commerce-sdk +- isomorphic SDK (currently not used atm): https://github.com/SalesforceCommerceCloud/commerce-sdk-isomorphic +- PWA Kit storefront example: https://pwa-kit.mobify-storefront.com/ + +## Training Material and Documentation: + +For a detailed introduction into commerce clouds feature set and data setup please refer to our Training Material and Documentation: + +- [Salesforce Trailhead for B2C Commerce Cloud](https://trailhead.salesforce.com/en/content/learn/trails/cc-overview) +- [Salesforce Trailhead for Development on B2C Commerce Cloud](https://trailhead.salesforce.com/en/content/learn/trails/develop-for-commerce-cloud) +- [B2C Commerce Cloud Documentation](https://documentation.b2c.commercecloud.salesforce.com/DOC1/index.jsp) +- [B2C Commerce Cloud Open Commerce API Doc](https://documentation.b2c.commercecloud.salesforce.com/DOC1/topic/com.demandware.dochelp/OCAPI/current/usage/OpenCommerceAPI.html?cp=0_15) +- [Developer Center for Commerce Cloud (Commerce APIs specifically)](https://developer.salesforce.com/docs/commerce/commerce-api/overview) +- [SLAS Org Admin Setup Guide](https://developer.salesforce.com/docs/commerce/commerce-api/references?meta=slas-admin:Summary) diff --git a/packages/sfcc/package.json b/packages/sfcc/package.json new file mode 100644 index 000000000..c04dc1909 --- /dev/null +++ b/packages/sfcc/package.json @@ -0,0 +1,80 @@ +{ + "name": "@vercel/commerce-sfcc", + "version": "0.0.1", + "license": "MIT", + "scripts": { + "release": "taskr release", + "build": "taskr build", + "dev": "taskr", + "types": "tsc --emitDeclarationOnly", + "prettier-fix": "prettier --write ." + }, + "sideEffects": false, + "type": "module", + "exports": { + ".": "./dist/index.js", + "./*": [ + "./dist/*.js", + "./dist/*/index.js" + ], + "./next.config": "./dist/next.config.cjs" + }, + "typesVersions": { + "*": { + "*": [ + "src/*", + "src/*/index" + ], + "next.config": [ + "dist/next.config.d.cts" + ] + } + }, + "files": [ + "dist" + ], + "publishConfig": { + "typesVersions": { + "*": { + "*": [ + "dist/*.d.ts", + "dist/*/index.d.ts" + ], + "next.config": [ + "dist/next.config.d.cts" + ] + } + } + }, + "dependencies": { + "@vercel/commerce": "^0.0.1", + "@vercel/fetch": "^6.1.1", + "commerce-sdk": "^2.7.0" + }, + "peerDependencies": { + "next": "^12", + "react": "^17", + "react-dom": "^17" + }, + "devDependencies": { + "@taskr/clear": "^1.1.0", + "@taskr/esnext": "^1.1.0", + "@taskr/watch": "^1.1.0", + "@types/node": "^17.0.8", + "@types/react": "^17.0.38", + "lint-staged": "^12.1.7", + "next": "^12.0.8", + "prettier": "^2.5.1", + "react": "^17.0.2", + "react-dom": "^17.0.2", + "taskr": "^1.1.0", + "taskr-swc": "^0.0.1", + "typescript": "^4.5.4" + }, + "lint-staged": { + "**/*.{js,jsx,ts,tsx,json}": [ + "prettier --write", + "git add" + ] + } +} diff --git a/packages/sfcc/src/api/endpoints/cart/index.ts b/packages/sfcc/src/api/endpoints/cart/index.ts new file mode 100644 index 000000000..491bf0ac9 --- /dev/null +++ b/packages/sfcc/src/api/endpoints/cart/index.ts @@ -0,0 +1 @@ +export default function noopApi(...args: any[]): void {} diff --git a/packages/sfcc/src/api/endpoints/catalog/products/get-products.ts b/packages/sfcc/src/api/endpoints/catalog/products/get-products.ts new file mode 100644 index 000000000..3b676e5ef --- /dev/null +++ b/packages/sfcc/src/api/endpoints/catalog/products/get-products.ts @@ -0,0 +1,32 @@ +import { normalizeSearchProducts } from '../../../utils/normalise-product' +import { ProductsEndpoint } from '.' + +const getProducts: ProductsEndpoint['handlers']['getProducts'] = async ({ + req, + res, + body: { search, categoryId, brandId, sort }, + config, +}) => { + const { sdk } = config + + // 'clothing' is our main category default, and a manually set category has priority + const searchTerm = categoryId ? (categoryId as string) : search || 'clothing' + + const searchClient = await sdk.getSearchClient() + // use SDK search API for initial products + const searchResults = await searchClient.productSearch({ + parameters: { + q: searchTerm, + limit: 20, + }, + }) + let products = [] + let found = false + if (searchResults.total) { + found = true + products = normalizeSearchProducts(searchResults.hits) as any[] + } + res.status(200).json({ data: { products, found } }) +} + +export default getProducts diff --git a/packages/sfcc/src/api/endpoints/catalog/products/index.ts b/packages/sfcc/src/api/endpoints/catalog/products/index.ts new file mode 100644 index 000000000..196eb04cb --- /dev/null +++ b/packages/sfcc/src/api/endpoints/catalog/products/index.ts @@ -0,0 +1,19 @@ +import type { SFCCProviderAPI } from '../../..' + +import { createEndpoint, GetAPISchema } from '@vercel/commerce/api' +import { ProductsSchema } from '@vercel/commerce/types/product' +import getProducts from './get-products' +import productsEndpoint from '@vercel/commerce/api/endpoints/catalog/products' + +export type ProductsAPI = GetAPISchema + +export type ProductsEndpoint = ProductsAPI['endpoint'] + +export const handlers: ProductsEndpoint['handlers'] = { getProducts } + +const productsApi = createEndpoint({ + handler: productsEndpoint, + handlers, +}) + +export default productsApi diff --git a/packages/sfcc/src/api/endpoints/checkout/index.ts b/packages/sfcc/src/api/endpoints/checkout/index.ts new file mode 100644 index 000000000..491bf0ac9 --- /dev/null +++ b/packages/sfcc/src/api/endpoints/checkout/index.ts @@ -0,0 +1 @@ +export default function noopApi(...args: any[]): void {} diff --git a/packages/sfcc/src/api/endpoints/customer/address.ts b/packages/sfcc/src/api/endpoints/customer/address.ts new file mode 100644 index 000000000..491bf0ac9 --- /dev/null +++ b/packages/sfcc/src/api/endpoints/customer/address.ts @@ -0,0 +1 @@ +export default function noopApi(...args: any[]): void {} diff --git a/packages/sfcc/src/api/endpoints/customer/card.ts b/packages/sfcc/src/api/endpoints/customer/card.ts new file mode 100644 index 000000000..491bf0ac9 --- /dev/null +++ b/packages/sfcc/src/api/endpoints/customer/card.ts @@ -0,0 +1 @@ +export default function noopApi(...args: any[]): void {} diff --git a/packages/sfcc/src/api/endpoints/customer/index.ts b/packages/sfcc/src/api/endpoints/customer/index.ts new file mode 100644 index 000000000..491bf0ac9 --- /dev/null +++ b/packages/sfcc/src/api/endpoints/customer/index.ts @@ -0,0 +1 @@ +export default function noopApi(...args: any[]): void {} diff --git a/packages/sfcc/src/api/endpoints/login/index.ts b/packages/sfcc/src/api/endpoints/login/index.ts new file mode 100644 index 000000000..491bf0ac9 --- /dev/null +++ b/packages/sfcc/src/api/endpoints/login/index.ts @@ -0,0 +1 @@ +export default function noopApi(...args: any[]): void {} diff --git a/packages/sfcc/src/api/endpoints/logout/index.ts b/packages/sfcc/src/api/endpoints/logout/index.ts new file mode 100644 index 000000000..491bf0ac9 --- /dev/null +++ b/packages/sfcc/src/api/endpoints/logout/index.ts @@ -0,0 +1 @@ +export default function noopApi(...args: any[]): void {} diff --git a/packages/sfcc/src/api/endpoints/signup/index.ts b/packages/sfcc/src/api/endpoints/signup/index.ts new file mode 100644 index 000000000..491bf0ac9 --- /dev/null +++ b/packages/sfcc/src/api/endpoints/signup/index.ts @@ -0,0 +1 @@ +export default function noopApi(...args: any[]): void {} diff --git a/packages/sfcc/src/api/endpoints/wishlist/index.tsx b/packages/sfcc/src/api/endpoints/wishlist/index.tsx new file mode 100644 index 000000000..491bf0ac9 --- /dev/null +++ b/packages/sfcc/src/api/endpoints/wishlist/index.tsx @@ -0,0 +1 @@ +export default function noopApi(...args: any[]): void {} diff --git a/packages/sfcc/src/api/index.ts b/packages/sfcc/src/api/index.ts new file mode 100644 index 000000000..50c6f468c --- /dev/null +++ b/packages/sfcc/src/api/index.ts @@ -0,0 +1,48 @@ +import type { CommerceAPI, CommerceAPIConfig } from '@vercel/commerce/api' +import { getCommerceApi as commerceApi } from '@vercel/commerce/api' +import createFetcher from './utils/fetch-local' +import sdk, { Sdk } from './utils/sfcc-sdk' + +import getAllPages from './operations/get-all-pages' +import getPage from './operations/get-page' +import getSiteInfo from './operations/get-site-info' +import getCustomerWishlist from './operations/get-customer-wishlist' +import getAllProductPaths from './operations/get-all-product-paths' +import getAllProducts from './operations/get-all-products' +import getProduct from './operations/get-product' + +export interface SFCCConfig extends CommerceAPIConfig { + sdk: Sdk +} +const config: SFCCConfig = { + commerceUrl: '', + apiToken: '', + cartCookie: '', + customerCookie: '', + cartCookieMaxAge: 2592000, + fetch: createFetcher(() => getCommerceApi().getConfig()), + sdk, // SalesForce Cloud Commerce API SDK +} + +const operations = { + getAllPages, + getPage, + getSiteInfo, + getCustomerWishlist, + getAllProductPaths, + getAllProducts, + getProduct, +} + +export const provider = { config, operations } + +export type Provider = typeof provider +export type SFCCProviderAPI

= CommerceAPI< + P | any +> + +export function getCommerceApi

( + customProvider: P = provider as any +): SFCCProviderAPI

{ + return commerceApi(customProvider as any) +} diff --git a/packages/sfcc/src/api/operations/get-all-pages.ts b/packages/sfcc/src/api/operations/get-all-pages.ts new file mode 100644 index 000000000..4465fe659 --- /dev/null +++ b/packages/sfcc/src/api/operations/get-all-pages.ts @@ -0,0 +1,19 @@ +export type Page = { url: string } +export type GetAllPagesResult = { pages: Page[] } +import type { SFCCConfig } from '../index' + +export default function getAllPagesOperation() { + function getAllPages({ + config, + preview, + }: { + url?: string + config?: Partial + preview?: boolean + }): Promise { + return Promise.resolve({ + pages: [], + }) + } + return getAllPages +} diff --git a/packages/sfcc/src/api/operations/get-all-product-paths.ts b/packages/sfcc/src/api/operations/get-all-product-paths.ts new file mode 100644 index 000000000..85dd4f597 --- /dev/null +++ b/packages/sfcc/src/api/operations/get-all-product-paths.ts @@ -0,0 +1,45 @@ +import { Product } from '@vercel/commerce/types/product' +import { OperationContext } from '@vercel/commerce/api/operations' +import { normalizeSearchProducts } from '../utils/normalise-product' +import { SFCCConfig } from '..' + +export type GetAllProductPathsResult = { + products: Array<{ path: string }> +} + +export default function getAllProductPathsOperation({ + commerce, +}: OperationContext) { + async function getAllProductPaths({ + query, + config, + variables, + }: { + query?: string + config?: SFCCConfig + variables?: any + } = {}): Promise { + // TODO: support locale + const { sdk, locale } = commerce.getConfig(config) as SFCCConfig + const searchClient = await sdk.getSearchClient() + + // use SDK search API for initial products same as getAllProductsOperation + const searchResults = await searchClient.productSearch({ + parameters: { q: 'dress', limit: variables?.first }, + }) + + let products = [] as Product[] + + if (searchResults.total) { + products = normalizeSearchProducts(searchResults.hits) + } + + return { + products: products?.map(({ slug }: Product) => ({ + path: `/${slug}`, + })), + } + } + + return getAllProductPaths +} diff --git a/packages/sfcc/src/api/operations/get-all-products.ts b/packages/sfcc/src/api/operations/get-all-products.ts new file mode 100644 index 000000000..cb891e794 --- /dev/null +++ b/packages/sfcc/src/api/operations/get-all-products.ts @@ -0,0 +1,40 @@ +import { Product } from '@vercel/commerce/types/product' +import { GetAllProductsOperation } from '@vercel/commerce/types/product' +import type { OperationContext } from '@vercel/commerce/api/operations' +import type { SFCCConfig } from '../index' +import { normalizeSearchProducts } from '../utils/normalise-product' + +export default function getAllProductsOperation({ + commerce, +}: OperationContext) { + async function getAllProducts({ + query = '', + variables, + config, + }: { + query?: string + variables?: T['variables'] + config?: Partial + preview?: boolean + } = {}): Promise<{ products: Product[] | any[] }> { + // TODO: support locale + const { sdk, locale } = commerce.getConfig(config) as SFCCConfig + const searchClient = await sdk.getSearchClient() + + // use SDK search API for initial products + const searchResults = await searchClient.productSearch({ + parameters: { q: 'dress', limit: variables?.first }, + }) + + let products = [] as Product[] + + if (searchResults.total) { + products = normalizeSearchProducts(searchResults.hits) + } + + return { + products: products, + } + } + return getAllProducts +} diff --git a/packages/sfcc/src/api/operations/get-customer-wishlist.ts b/packages/sfcc/src/api/operations/get-customer-wishlist.ts new file mode 100644 index 000000000..8c34b9e87 --- /dev/null +++ b/packages/sfcc/src/api/operations/get-customer-wishlist.ts @@ -0,0 +1,6 @@ +export default function getCustomerWishlistOperation() { + function getCustomerWishlist(): any { + return { wishlist: {} } + } + return getCustomerWishlist +} diff --git a/packages/sfcc/src/api/operations/get-page.ts b/packages/sfcc/src/api/operations/get-page.ts new file mode 100644 index 000000000..b0cfdf58f --- /dev/null +++ b/packages/sfcc/src/api/operations/get-page.ts @@ -0,0 +1,13 @@ +export type Page = any +export type GetPageResult = { page?: Page } + +export type PageVariables = { + id: number +} + +export default function getPageOperation() { + function getPage(): Promise { + return Promise.resolve({}) + } + return getPage +} diff --git a/packages/sfcc/src/api/operations/get-product.ts b/packages/sfcc/src/api/operations/get-product.ts new file mode 100644 index 000000000..72449c56b --- /dev/null +++ b/packages/sfcc/src/api/operations/get-product.ts @@ -0,0 +1,33 @@ +import { GetProductOperation, Product } from '@vercel/commerce/types/product' +import type { SFCCConfig } from '../index' +import type { OperationContext } from '@vercel/commerce/api/operations' +import { normalizeProduct } from '../utils/normalise-product' + +export default function getProductOperation({ + commerce, +}: OperationContext) { + async function getProduct({ + query = '', + variables, + config, + }: { + query?: string + variables?: T['variables'] + config?: Partial + preview?: boolean + } = {}): Promise { + // TODO: support locale + const { sdk, locale } = commerce.getConfig(config) as SFCCConfig + const shopperProductsClient = await sdk.getshopperProductsClient() + const product = await shopperProductsClient.getProduct({ + parameters: { id: variables?.slug as string }, + }) + const normalizedProduct = normalizeProduct(product) + + return { + product: normalizedProduct, + } + } + + return getProduct +} diff --git a/packages/sfcc/src/api/operations/get-site-info.ts b/packages/sfcc/src/api/operations/get-site-info.ts new file mode 100644 index 000000000..43a74b1ef --- /dev/null +++ b/packages/sfcc/src/api/operations/get-site-info.ts @@ -0,0 +1,43 @@ +import { OperationContext } from '@vercel/commerce/api/operations' +import { Category } from '@vercel/commerce/types/site' +import { SFCCConfig } from '../index' + +export type GetSiteInfoResult< + T extends { categories: any[]; brands: any[] } = { + categories: Category[] + brands: any[] + } +> = T + +export default function getSiteInfoOperation({}: OperationContext) { + function getSiteInfo({ + query, + variables, + config: cfg, + }: { + query?: string + variables?: any + config?: Partial + preview?: boolean + } = {}): Promise { + return Promise.resolve({ + categories: [ + { + id: 'new-arrivals', + name: 'New Arrivals', + slug: 'new-arrivals', + path: '/new-arrivals', + }, + { + id: 'womens-clothing-dresses', + name: 'Womens Clothing Dresses', + slug: 'womens-clothing-dresses', + path: '/womens-clothing-dresses', + }, + ], + brands: [], + }) + } + + return getSiteInfo +} diff --git a/packages/sfcc/src/api/operations/index.ts b/packages/sfcc/src/api/operations/index.ts new file mode 100644 index 000000000..086fdf83a --- /dev/null +++ b/packages/sfcc/src/api/operations/index.ts @@ -0,0 +1,6 @@ +export { default as getPage } from './get-page' +export { default as getSiteInfo } from './get-site-info' +export { default as getAllPages } from './get-all-pages' +export { default as getProduct } from './get-product' +export { default as getAllProducts } from './get-all-products' +export { default as getAllProductPaths } from './get-all-product-paths' diff --git a/packages/sfcc/src/api/utils/fetch-local.ts b/packages/sfcc/src/api/utils/fetch-local.ts new file mode 100644 index 000000000..5a2bab076 --- /dev/null +++ b/packages/sfcc/src/api/utils/fetch-local.ts @@ -0,0 +1,34 @@ +import { FetcherError } from '@vercel/commerce/utils/errors' +import type { GraphQLFetcher } from '@vercel/commerce/api' +import type { SFCCConfig } from '../index' +import fetch from './fetch' + +const fetchGraphqlApi: (getConfig: () => SFCCConfig) => GraphQLFetcher = + (getConfig) => + async (query: string, { variables, preview } = {}, fetchOptions) => { + const config = getConfig() + const res = await fetch(config.commerceUrl, { + ...fetchOptions, + method: 'POST', + headers: { + ...fetchOptions?.headers, + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + query, + variables, + }), + }) + + const json = await res.json() + if (json.errors) { + throw new FetcherError({ + errors: json.errors ?? [{ message: 'Failed to fetch for API' }], + status: res.status, + }) + } + + return { data: json.data, res } + } + +export default fetchGraphqlApi diff --git a/packages/sfcc/src/api/utils/fetch.ts b/packages/sfcc/src/api/utils/fetch.ts new file mode 100644 index 000000000..9d9fff3ed --- /dev/null +++ b/packages/sfcc/src/api/utils/fetch.ts @@ -0,0 +1,3 @@ +import zeitFetch from '@vercel/fetch' + +export default zeitFetch() diff --git a/packages/sfcc/src/api/utils/get-auth-token.ts b/packages/sfcc/src/api/utils/get-auth-token.ts new file mode 100644 index 000000000..373d6c6cd --- /dev/null +++ b/packages/sfcc/src/api/utils/get-auth-token.ts @@ -0,0 +1,42 @@ +import { ClientConfig, Customer } from 'commerce-sdk' + +// client configuration parameters +export const clientConfig: ClientConfig = { + headers: { + authorization: ``, + }, + parameters: { + clientId: process.env.SFCC_CLIENT_ID || '', + organizationId: process.env.SFCC_ORG_ID || '', + shortCode: process.env.SFCC_SHORT_CODE || '', + siteId: process.env.SFCC_SITE_ID || '', + }, +} + +/** + * Get the shopper or guest JWT/access token, along with a refresh token, using client credentials + * + * @returns guest user authorization token + */ +export async function getGuestUserAuthToken(): Promise { + const credentials = `${process.env.SFCC_CLIENT_ID}:${process.env.SFCC_CLIENT_SECRET}` + const base64data = Buffer.from(credentials).toString('base64') + const headers = { Authorization: `Basic ${base64data}` } + const client = new Customer.ShopperLogin(clientConfig) + + return await client.getAccessToken({ + headers, + body: { + grant_type: 'client_credentials', + }, + }) +} + +export const getConfigAuth = async () => { + const shopperToken = await getGuestUserAuthToken() + const configAuth = { + ...clientConfig, + headers: { authorization: `Bearer ${shopperToken.access_token}` }, + } + return configAuth +} diff --git a/packages/sfcc/src/api/utils/normalise-product.ts b/packages/sfcc/src/api/utils/normalise-product.ts new file mode 100644 index 000000000..b8d0e2ed4 --- /dev/null +++ b/packages/sfcc/src/api/utils/normalise-product.ts @@ -0,0 +1,96 @@ +import { Product as SFCCProduct, Search } from 'commerce-sdk' +import type { + Product, + ProductImage, + ProductOption, + ProductVariant, +} from '@vercel/commerce/types/product' + +const normaliseOptions = ( + options: SFCCProduct.ShopperProducts.Product['variationAttributes'] +): Product['options'] => { + if (!Array.isArray(options)) return [] + + return options.map((option) => { + return { + id: option.id, + displayName: option.name as string, + values: option.values!.map((value) => ({ label: value.name })), + } as ProductOption + }) +} + +const normaliseVariants = ( + variants: SFCCProduct.ShopperProducts.Product['variants'] +): Product['variants'] => { + if (!Array.isArray(variants)) return [] + + return variants.map((variant) => { + const options = [] as ProductOption[] + + if (variant.variationValues) { + for (const [key, value] of Object.entries(variant.variationValues)) { + const variantOptionObject = { + id: `${variant.productId}-${key}`, + displayName: key, + values: [ + { + label: value, + }, + ], + } + options.push(variantOptionObject) + } + } + + return { + id: variant.productId, + options, + } as ProductVariant + }) +} + +export function normalizeProduct( + product: SFCCProduct.ShopperProducts.Product +): Product { + return { + id: product.id, + // TODO: use `name-ID` as a virtual slug (for search 1:1) + slug: product.id, // use product ID as a slug + name: product.name!, + description: product.longDescription!, + price: { + value: product.price!, + currencyCode: product.currency, + }, + images: product.imageGroups![0].images.map((image) => ({ + url: image.disBaseLink, + altText: image.title, + })) as ProductImage[], + variants: normaliseVariants(product.variants), + options: normaliseOptions(product.variationAttributes), + } +} + +export function normalizeSearchProducts( + products: Search.ShopperSearch.ProductSearchHit[] +): Product[] { + return products.map((product) => ({ + id: product.productId, + slug: product.productId, // use product ID as a slug + name: product.productName!, + description: '', + price: { + value: product.price!, + currencyCode: product.currency, + }, + images: [ + { + url: product.image!.link, + altText: product.productName, + } as ProductImage, + ], + variants: normaliseVariants(product.variants), + options: normaliseOptions(product.variationAttributes), + })) +} diff --git a/packages/sfcc/src/api/utils/sfcc-sdk.ts b/packages/sfcc/src/api/utils/sfcc-sdk.ts new file mode 100644 index 000000000..8d20b677e --- /dev/null +++ b/packages/sfcc/src/api/utils/sfcc-sdk.ts @@ -0,0 +1,19 @@ +import { Product, Search } from 'commerce-sdk' +import { getConfigAuth } from './get-auth-token' + +const getSearchClient = async () => { + const configAuth = await getConfigAuth() + return new Search.ShopperSearch(configAuth) +} + +const getshopperProductsClient = async () => { + const configAuth = await getConfigAuth() + return new Product.ShopperProducts(configAuth) +} + +export const sdk = { + getshopperProductsClient, + getSearchClient, +} +export type Sdk = typeof sdk +export default sdk diff --git a/packages/sfcc/src/auth/index.ts b/packages/sfcc/src/auth/index.ts new file mode 100644 index 000000000..36e757a89 --- /dev/null +++ b/packages/sfcc/src/auth/index.ts @@ -0,0 +1,3 @@ +export { default as useLogin } from './use-login' +export { default as useLogout } from './use-logout' +export { default as useSignup } from './use-signup' diff --git a/packages/sfcc/src/auth/use-login.tsx b/packages/sfcc/src/auth/use-login.tsx new file mode 100644 index 000000000..20e3ed229 --- /dev/null +++ b/packages/sfcc/src/auth/use-login.tsx @@ -0,0 +1,16 @@ +import { MutationHook } from '@vercel/commerce/utils/types' +import useLogin, { UseLogin } from '@vercel/commerce/auth/use-login' + +export default useLogin as UseLogin + +export const handler: MutationHook = { + fetchOptions: { + query: '', + }, + async fetcher() { + return null + }, + useHook: () => () => { + return async function () {} + }, +} diff --git a/packages/sfcc/src/auth/use-logout.tsx b/packages/sfcc/src/auth/use-logout.tsx new file mode 100644 index 000000000..4e74908f3 --- /dev/null +++ b/packages/sfcc/src/auth/use-logout.tsx @@ -0,0 +1,17 @@ +import { MutationHook } from '@vercel/commerce/utils/types' +import useLogout, { UseLogout } from '@vercel/commerce/auth/use-logout' + +export default useLogout as UseLogout + +export const handler: MutationHook = { + fetchOptions: { + query: '', + }, + async fetcher() { + return null + }, + useHook: + ({ fetch }) => + () => + async () => {}, +} diff --git a/packages/sfcc/src/auth/use-signup.tsx b/packages/sfcc/src/auth/use-signup.tsx new file mode 100644 index 000000000..e48811403 --- /dev/null +++ b/packages/sfcc/src/auth/use-signup.tsx @@ -0,0 +1,19 @@ +import { useCallback } from 'react' +import useCustomer from '../customer/use-customer' +import { MutationHook } from '@vercel/commerce/utils/types' +import useSignup, { UseSignup } from '@vercel/commerce/auth/use-signup' + +export default useSignup as UseSignup + +export const handler: MutationHook = { + fetchOptions: { + query: '', + }, + async fetcher() { + return null + }, + useHook: + ({ fetch }) => + () => + () => {}, +} diff --git a/packages/sfcc/src/cart/index.ts b/packages/sfcc/src/cart/index.ts new file mode 100644 index 000000000..3b8ba990e --- /dev/null +++ b/packages/sfcc/src/cart/index.ts @@ -0,0 +1,4 @@ +export { default as useCart } from './use-cart' +export { default as useAddItem } from './use-add-item' +export { default as useRemoveItem } from './use-remove-item' +export { default as useUpdateItem } from './use-update-item' diff --git a/packages/sfcc/src/cart/use-add-item.tsx b/packages/sfcc/src/cart/use-add-item.tsx new file mode 100644 index 000000000..2be6e0aaa --- /dev/null +++ b/packages/sfcc/src/cart/use-add-item.tsx @@ -0,0 +1,17 @@ +import useAddItem, { UseAddItem } from '@vercel/commerce/cart/use-add-item' +import { MutationHook } from '@vercel/commerce/utils/types' + +export default useAddItem as UseAddItem +export const handler: MutationHook = { + fetchOptions: { + query: '', + }, + async fetcher({ input, options, fetch }) {}, + useHook: + ({ fetch }) => + () => { + return async function addItem() { + return {} + } + }, +} diff --git a/packages/sfcc/src/cart/use-cart.tsx b/packages/sfcc/src/cart/use-cart.tsx new file mode 100644 index 000000000..8f92de3c9 --- /dev/null +++ b/packages/sfcc/src/cart/use-cart.tsx @@ -0,0 +1,42 @@ +import { useMemo } from 'react' +import { SWRHook } from '@vercel/commerce/utils/types' +import useCart, { UseCart } from '@vercel/commerce/cart/use-cart' + +export default useCart as UseCart + +export const handler: SWRHook = { + fetchOptions: { + query: '', + }, + async fetcher() { + return { + id: '', + createdAt: '', + currency: { code: '' }, + taxesIncluded: '', + lineItems: [], + lineItemsSubtotalPrice: '', + subtotalPrice: 0, + totalPrice: 0, + } + }, + useHook: + ({ useData }) => + (input) => { + return useMemo( + () => + Object.create( + {}, + { + isEmpty: { + get() { + return true + }, + enumerable: true, + }, + } + ), + [] + ) + }, +} diff --git a/packages/sfcc/src/cart/use-remove-item.tsx b/packages/sfcc/src/cart/use-remove-item.tsx new file mode 100644 index 000000000..92d52c997 --- /dev/null +++ b/packages/sfcc/src/cart/use-remove-item.tsx @@ -0,0 +1,20 @@ +import { MutationHook } from '@vercel/commerce/utils/types' +import useRemoveItem, { + UseRemoveItem, +} from '@vercel/commerce/cart/use-remove-item' + +export default useRemoveItem as UseRemoveItem + +export const handler: MutationHook = { + fetchOptions: { + query: '', + }, + async fetcher({ input, options, fetch }) {}, + useHook: + ({ fetch }) => + () => { + return async function removeItem(input) { + return {} + } + }, +} diff --git a/packages/sfcc/src/cart/use-update-item.tsx b/packages/sfcc/src/cart/use-update-item.tsx new file mode 100644 index 000000000..950f422e1 --- /dev/null +++ b/packages/sfcc/src/cart/use-update-item.tsx @@ -0,0 +1,20 @@ +import { MutationHook } from '@vercel/commerce/utils/types' +import useUpdateItem, { + UseUpdateItem, +} from '@vercel/commerce/cart/use-update-item' + +export default useUpdateItem as UseUpdateItem + +export const handler: MutationHook = { + fetchOptions: { + query: '', + }, + async fetcher({ input, options, fetch }) {}, + useHook: + ({ fetch }) => + () => { + return async function addItem() { + return {} + } + }, +} diff --git a/packages/sfcc/src/checkout/use-checkout.tsx b/packages/sfcc/src/checkout/use-checkout.tsx new file mode 100644 index 000000000..76997be73 --- /dev/null +++ b/packages/sfcc/src/checkout/use-checkout.tsx @@ -0,0 +1,16 @@ +import { SWRHook } from '@vercel/commerce/utils/types' +import useCheckout, { + UseCheckout, +} from '@vercel/commerce/checkout/use-checkout' + +export default useCheckout as UseCheckout + +export const handler: SWRHook = { + fetchOptions: { + query: '', + }, + async fetcher({ input, options, fetch }) {}, + useHook: + ({ useData }) => + async (input) => ({}), +} diff --git a/packages/sfcc/src/commerce.config.json b/packages/sfcc/src/commerce.config.json new file mode 100644 index 000000000..1d2064520 --- /dev/null +++ b/packages/sfcc/src/commerce.config.json @@ -0,0 +1,10 @@ +{ + "provider": "sfcc", + "features": { + "wishlist": false, + "cart": false, + "search": true, + "customerAuth": false, + "customCheckout": false + } +} diff --git a/packages/sfcc/src/customer/address/use-add-item.tsx b/packages/sfcc/src/customer/address/use-add-item.tsx new file mode 100644 index 000000000..4f85c8472 --- /dev/null +++ b/packages/sfcc/src/customer/address/use-add-item.tsx @@ -0,0 +1,17 @@ +import useAddItem, { + UseAddItem, +} from '@vercel/commerce/customer/address/use-add-item' +import { MutationHook } from '@vercel/commerce/utils/types' + +export default useAddItem as UseAddItem + +export const handler: MutationHook = { + fetchOptions: { + query: '', + }, + async fetcher({ input, options, fetch }) {}, + useHook: + ({ fetch }) => + () => + async () => ({}), +} diff --git a/packages/sfcc/src/customer/card/use-add-item.tsx b/packages/sfcc/src/customer/card/use-add-item.tsx new file mode 100644 index 000000000..77d149eff --- /dev/null +++ b/packages/sfcc/src/customer/card/use-add-item.tsx @@ -0,0 +1,17 @@ +import useAddItem, { + UseAddItem, +} from '@vercel/commerce/customer/card/use-add-item' +import { MutationHook } from '@vercel/commerce/utils/types' + +export default useAddItem as UseAddItem + +export const handler: MutationHook = { + fetchOptions: { + query: '', + }, + async fetcher({ input, options, fetch }) {}, + useHook: + ({ fetch }) => + () => + async () => ({}), +} diff --git a/packages/sfcc/src/customer/index.ts b/packages/sfcc/src/customer/index.ts new file mode 100644 index 000000000..6c903ecc5 --- /dev/null +++ b/packages/sfcc/src/customer/index.ts @@ -0,0 +1 @@ +export { default as useCustomer } from './use-customer' diff --git a/packages/sfcc/src/customer/use-customer.tsx b/packages/sfcc/src/customer/use-customer.tsx new file mode 100644 index 000000000..04c48943d --- /dev/null +++ b/packages/sfcc/src/customer/use-customer.tsx @@ -0,0 +1,17 @@ +import { SWRHook } from '@vercel/commerce/utils/types' +import useCustomer, { + UseCustomer, +} from '@vercel/commerce/customer/use-customer' + +export default useCustomer as UseCustomer +export const handler: SWRHook = { + fetchOptions: { + query: '', + }, + async fetcher({ input, options, fetch }) {}, + useHook: () => () => { + return async function addItem() { + return {} + } + }, +} diff --git a/packages/sfcc/src/fetcher.ts b/packages/sfcc/src/fetcher.ts new file mode 100644 index 000000000..1da35718e --- /dev/null +++ b/packages/sfcc/src/fetcher.ts @@ -0,0 +1,17 @@ +import { Fetcher } from '@vercel/commerce/utils/types' + +const clientFetcher: Fetcher = async ({ method, url, body }) => { + const response = await fetch(url!, { + method, + body: body ? JSON.stringify(body) : undefined, + headers: { + 'Content-Type': 'application/json', + }, + }) + .then((response) => response.json()) + .then((response) => response.data) + + return response +} + +export default clientFetcher diff --git a/packages/sfcc/src/index.tsx b/packages/sfcc/src/index.tsx new file mode 100644 index 000000000..561f641f5 --- /dev/null +++ b/packages/sfcc/src/index.tsx @@ -0,0 +1,12 @@ +import { + getCommerceProvider, + useCommerce as useCoreCommerce, +} from '@vercel/commerce' +import { sfccProvider, SfccProvider } from './provider' + +export { sfccProvider } +export type { SfccProvider } + +export const CommerceProvider = getCommerceProvider(sfccProvider) + +export const useCommerce = () => useCoreCommerce() diff --git a/packages/sfcc/src/next.config.cjs b/packages/sfcc/src/next.config.cjs new file mode 100644 index 000000000..6c42018df --- /dev/null +++ b/packages/sfcc/src/next.config.cjs @@ -0,0 +1,12 @@ +const commerce = require('./commerce.config.json') + +module.exports = { + commerce, + images: { + domains: [ + 'localhost', + 'edge.disstg.commercecloud.salesforce.com', + 'zzte-053.sandbox.us02.dx.commercecloud.salesforce.com', + ], + }, +} diff --git a/packages/sfcc/src/product/index.ts b/packages/sfcc/src/product/index.ts new file mode 100644 index 000000000..426a3edcd --- /dev/null +++ b/packages/sfcc/src/product/index.ts @@ -0,0 +1,2 @@ +export { default as usePrice } from './use-price' +export { default as useSearch } from './use-search' diff --git a/packages/sfcc/src/product/use-price.tsx b/packages/sfcc/src/product/use-price.tsx new file mode 100644 index 000000000..fd42d7033 --- /dev/null +++ b/packages/sfcc/src/product/use-price.tsx @@ -0,0 +1,2 @@ +export * from '@vercel/commerce/product/use-price' +export { default } from '@vercel/commerce/product/use-price' diff --git a/packages/sfcc/src/product/use-search.tsx b/packages/sfcc/src/product/use-search.tsx new file mode 100644 index 000000000..bb5e97160 --- /dev/null +++ b/packages/sfcc/src/product/use-search.tsx @@ -0,0 +1,42 @@ +import { SWRHook } from '@vercel/commerce/utils/types' +import useSearch, { UseSearch } from '@vercel/commerce/product/use-search' +import { SearchProductsHook } from '@vercel/commerce/types/product' +export default useSearch as UseSearch + +export const handler: SWRHook = { + fetchOptions: { + url: '/api/catalog/products', + method: 'GET', + }, + fetcher({ input: { search, categoryId, brandId, sort }, options, fetch }) { + console.log('search', search, categoryId, options) + // Use a dummy base as we only care about the relative path + const url = new URL(options.url!, 'http://a') + + if (search) url.searchParams.set('search', String(search)) + if (categoryId) url.searchParams.set('categoryId', String(categoryId)) + if (brandId) url.searchParams.set('brandId', String(brandId)) + if (sort) url.searchParams.set('sort', String(sort)) + + return fetch({ + url: url.pathname + url.search, + method: options.method, + }) + }, + useHook: + ({ useData }) => + (input = {}) => { + return useData({ + input: [ + ['search', input.search], + ['categoryId', input.categoryId], + ['brandId', input.brandId], + ['sort', input.sort], + ], + swrOptions: { + revalidateOnFocus: false, + ...input.swrOptions, + }, + }) + }, +} diff --git a/packages/sfcc/src/provider.ts b/packages/sfcc/src/provider.ts new file mode 100644 index 000000000..47063f82f --- /dev/null +++ b/packages/sfcc/src/provider.ts @@ -0,0 +1,22 @@ +import fetcher from './fetcher' +import { handler as useCart } from './cart/use-cart' +import { handler as useAddItem } from './cart/use-add-item' +import { handler as useUpdateItem } from './cart/use-update-item' +import { handler as useRemoveItem } from './cart/use-remove-item' +import { handler as useCustomer } from './customer/use-customer' +import { handler as useSearch } from './product/use-search' +import { handler as useLogin } from './auth/use-login' +import { handler as useLogout } from './auth/use-logout' +import { handler as useSignup } from './auth/use-signup' + +export const sfccProvider = { + locale: 'en-us', + cartCookie: 'session', + fetcher, + cart: { useCart, useAddItem, useUpdateItem, useRemoveItem }, + customer: { useCustomer }, + products: { useSearch }, + auth: { useLogin, useLogout, useSignup }, +} + +export type SfccProvider = typeof sfccProvider diff --git a/packages/sfcc/src/wishlist/use-add-item.tsx b/packages/sfcc/src/wishlist/use-add-item.tsx new file mode 100644 index 000000000..75f067c3a --- /dev/null +++ b/packages/sfcc/src/wishlist/use-add-item.tsx @@ -0,0 +1,13 @@ +import { useCallback } from 'react' + +export function emptyHook() { + const useEmptyHook = async (options = {}) => { + return useCallback(async function () { + return Promise.resolve() + }, []) + } + + return useEmptyHook +} + +export default emptyHook diff --git a/packages/sfcc/src/wishlist/use-remove-item.tsx b/packages/sfcc/src/wishlist/use-remove-item.tsx new file mode 100644 index 000000000..a2d3a8a05 --- /dev/null +++ b/packages/sfcc/src/wishlist/use-remove-item.tsx @@ -0,0 +1,17 @@ +import { useCallback } from 'react' + +type Options = { + includeProducts?: boolean +} + +export function emptyHook(options?: Options) { + const useEmptyHook = async ({ id }: { id: string | number }) => { + return useCallback(async function () { + return Promise.resolve() + }, []) + } + + return useEmptyHook +} + +export default emptyHook diff --git a/packages/sfcc/src/wishlist/use-wishlist.tsx b/packages/sfcc/src/wishlist/use-wishlist.tsx new file mode 100644 index 000000000..b2785d46f --- /dev/null +++ b/packages/sfcc/src/wishlist/use-wishlist.tsx @@ -0,0 +1,43 @@ +import { HookFetcher } from '@vercel/commerce/utils/types' +import type { Product } from '@vercel/commerce/types/product' + +const defaultOpts = {} + +export type Wishlist = { + items: [ + { + product_id: number + variant_id: number + id: number + product: Product + } + ] +} + +export interface UseWishlistOptions { + includeProducts?: boolean +} + +export interface UseWishlistInput extends UseWishlistOptions { + customerId?: number +} + +export const fetcher: HookFetcher = () => { + return null +} + +export function extendHook( + customFetcher: typeof fetcher, + // swrOptions?: SwrOptions + swrOptions?: any +) { + const useWishlist = ({ includeProducts }: UseWishlistOptions = {}) => { + return { data: null } + } + + useWishlist.extend = extendHook + + return useWishlist +} + +export default extendHook(fetcher) diff --git a/packages/sfcc/taskfile.js b/packages/sfcc/taskfile.js new file mode 100644 index 000000000..39b1b2a86 --- /dev/null +++ b/packages/sfcc/taskfile.js @@ -0,0 +1,20 @@ +export async function build(task, opts) { + await task + .source('src/**/*.+(ts|tsx|js)') + .swc({ dev: opts.dev, outDir: 'dist', baseUrl: 'src' }) + .target('dist') + .source('src/**/*.+(cjs|json)') + .target('dist') + task.$.log('Compiled src files') +} + +export async function release(task) { + await task.clear('dist').start('build') +} + +export default async function dev(task) { + const opts = { dev: true } + await task.clear('dist') + await task.start('build', opts) + await task.watch('src/**/*.+(ts|tsx|js|cjs|json)', 'build', opts) +} diff --git a/packages/sfcc/tsconfig.json b/packages/sfcc/tsconfig.json new file mode 100644 index 000000000..cd04ab2ff --- /dev/null +++ b/packages/sfcc/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "esnext", + "module": "esnext", + "outDir": "dist", + "baseUrl": "src", + "lib": ["dom", "dom.iterable", "esnext"], + "declaration": true, + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "esModuleInterop": true, + "moduleResolution": "node", + "resolveJsonModule": true, + "incremental": true, + "jsx": "react-jsx" + }, + "include": ["src"], + "exclude": ["node_modules", "dist"] +} diff --git a/site/.env.template b/site/.env.template index 47b3df3c4..a9eb798fe 100644 --- a/site/.env.template +++ b/site/.env.template @@ -9,6 +9,7 @@ # @vercel/commerce-vendure # @vercel/commerce-kibocommerce # @vercel/commerce-commercejs +# @vercel/commerce-sfcc COMMERCE_PROVIDER= BIGCOMMERCE_STOREFRONT_API_URL= @@ -47,3 +48,9 @@ KIBO_API_HOST= NEXT_PUBLIC_COMMERCEJS_PUBLIC_KEY= NEXT_PUBLIC_COMMERCEJS_DEPLOYMENT_URL= + +SFCC_CLIENT_ID= +SFCC_CLIENT_SECRET= +SFCC_ORG_ID= +SFCC_SHORT_CODE= +SFCC_SITE_ID=RefArch \ No newline at end of file diff --git a/site/commerce-config.js b/site/commerce-config.js index d52797e51..f92f221d0 100644 --- a/site/commerce-config.js +++ b/site/commerce-config.js @@ -19,6 +19,7 @@ const PROVIDERS = [ '@vercel/commerce-kibocommerce', '@vercel/commerce-spree', '@vercel/commerce-commercejs', + '@vercel/commerce-sfcc', ] function getProviderName() { diff --git a/yarn.lock b/yarn.lock index fc850a7a8..260ee460f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -500,6 +500,28 @@ "@babel/runtime" "^7.7.4" axios "^0.21.1" +"@commerce-apps/core@^1.5.5": + version "1.5.5" + resolved "https://registry.yarnpkg.com/@commerce-apps/core/-/core-1.5.5.tgz#e82e3c3cbb2a184789eeb8668d004a799792f9d0" + integrity sha512-AlNLY2Mv0/2sNbJq74MHrYKiCXyJytekgfrxUcaYARnB8KGvexV4MhHiVYj1TYVINroLrO4rW0D9uKLCn7nHxA== + dependencies: + "@keyv/redis" "^2.2.0" + dotenv "^8.6.0" + fetch-to-curl "^0.5.2" + ioredis "^4.28.1" + jsonwebtoken "^8.5.1" + keyv "^4.0.4" + lodash "^4.17.21" + loglevel "^1.8.0" + make-fetch-happen "^8.0.14" + minipass-fetch "^1.4.1" + qs "^6.10.2" + quick-lru "^5.1.1" + retry "^0.13.1" + snyk "^1.759.0" + ssri "^8.0.1" + tslib "^1.14.1" + "@endemolshinegroup/cosmiconfig-typescript-loader@3.0.2": version "3.0.2" resolved "https://registry.yarnpkg.com/@endemolshinegroup/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-3.0.2.tgz#eea4635828dde372838b0909693ebd9aafeec22d" @@ -525,6 +547,11 @@ minimatch "^3.0.4" strip-json-comments "^3.1.1" +"@gar/promisify@^1.0.1": + version "1.1.3" + resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6" + integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw== + "@graphql-codegen/cli@^2.3.1": version "2.4.0" resolved "https://registry.yarnpkg.com/@graphql-codegen/cli/-/cli-2.4.0.tgz#7df3ee2bdd5b88a5904ee6f52eafeb370ef70e51" @@ -879,6 +906,13 @@ resolved "https://registry.yarnpkg.com/@iarna/toml/-/toml-2.2.5.tgz#b32366c89b43c6f8cefbdefac778b9c828e3ba8c" integrity sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg== +"@keyv/redis@^2.2.0": + version "2.2.3" + resolved "https://registry.yarnpkg.com/@keyv/redis/-/redis-2.2.3.tgz#af5b1ea32d847a63ce24012844af7323b3c421a7" + integrity sha512-d9Maf1LzT6Ti5hWsVzaWFriFmXrscK1eUl/etNquQgAJxH7Drecbn+uNZXMc6xb78Ju9szy0fD9RAp/G9RzAdg== + dependencies: + ioredis "^4.28.5" + "@n1ru4l/graphql-live-query@^0.9.0": version "0.9.0" resolved "https://registry.yarnpkg.com/@n1ru4l/graphql-live-query/-/graphql-live-query-0.9.0.tgz#defaebdd31f625bee49e6745934f36312532b2bc" @@ -984,6 +1018,22 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" +"@npmcli/fs@^1.0.0": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-1.1.1.tgz#72f719fe935e687c56a4faecf3c03d06ba593257" + integrity sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ== + dependencies: + "@gar/promisify" "^1.0.1" + semver "^7.3.5" + +"@npmcli/move-file@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-1.1.2.tgz#1a82c3e372f7cae9253eb66d72543d6b8685c674" + integrity sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg== + dependencies: + mkdirp "^1.0.4" + rimraf "^3.0.2" + "@polka/url@^1.0.0-next.20": version "1.0.0-next.21" resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.21.tgz#5de5a2385a35309427f6011992b544514d559aa1" @@ -1426,6 +1476,11 @@ dependencies: chokidar "^1.7.0" +"@tootallnate/once@1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" + integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== + "@tootallnate/once@2": version "2.0.0" resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf" @@ -1694,7 +1749,7 @@ acorn@^8.0.4, acorn@^8.7.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf" integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ== -agent-base@6: +agent-base@6, agent-base@^6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== @@ -1708,6 +1763,15 @@ agentkeepalive@3.4.1: dependencies: humanize-ms "^1.2.1" +agentkeepalive@^4.1.3: + version "4.2.1" + resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.2.1.tgz#a7975cbb9f83b367f06c90cc51ff28fe7d499717" + integrity sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA== + dependencies: + debug "^4.1.0" + depd "^1.1.2" + humanize-ms "^1.2.1" + aggregate-error@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" @@ -2180,6 +2244,30 @@ buffer@^5.5.0, buffer@^5.7.0: base64-js "^1.3.1" ieee754 "^1.1.13" +cacache@^15.0.5: + version "15.3.0" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-15.3.0.tgz#dc85380fb2f556fe3dda4c719bfa0ec875a7f1eb" + integrity sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ== + dependencies: + "@npmcli/fs" "^1.0.0" + "@npmcli/move-file" "^1.0.1" + chownr "^2.0.0" + fs-minipass "^2.0.0" + glob "^7.1.4" + infer-owner "^1.0.4" + lru-cache "^6.0.0" + minipass "^3.1.1" + minipass-collect "^1.0.2" + minipass-flush "^1.0.5" + minipass-pipeline "^1.2.2" + mkdirp "^1.0.3" + p-map "^4.0.0" + promise-inflight "^1.0.1" + rimraf "^3.0.2" + ssri "^8.0.1" + tar "^6.0.2" + unique-filename "^1.1.1" + cache-base@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" @@ -2351,6 +2439,11 @@ chokidar@^3.5.2: optionalDependencies: fsevents "~2.3.2" +chownr@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" + integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== + class-utils@^0.3.5: version "0.3.6" resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" @@ -2454,6 +2547,11 @@ clsx@^1.1.1: resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.1.1.tgz#98b3134f9abbdf23b2663491ace13c5c03a73188" integrity sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA== +cluster-key-slot@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz#30474b2a981fb12172695833052bc0d01336d10d" + integrity sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw== + code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" @@ -2518,6 +2616,16 @@ commander@^8.3.0: resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== +commerce-sdk@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/commerce-sdk/-/commerce-sdk-2.7.0.tgz#a66ed6a29d74500ca91e9e518ba1a389e9327794" + integrity sha512-jMOSKhXOQaSSSOa/G/NfklAP2TUCvAOEON/Af/81As36+KwQLK1LkdfhKnBW+XsIHa3hXrC2ED3VZZhq7c96oA== + dependencies: + "@commerce-apps/core" "^1.5.5" + lodash "^4.17.21" + retry "^0.12.0" + tslib "^2.3.1" + common-tags@1.8.2, common-tags@^1.8.0: version "1.8.2" resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.2.tgz#94ebb3c076d26032745fd54face7f688ef5ac9c6" @@ -2797,6 +2905,16 @@ delayed-stream@~1.0.0: resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= +denque@^1.1.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/denque/-/denque-1.5.1.tgz#07f670e29c9a78f8faecb2566a1e2c11929c5cbf" + integrity sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw== + +depd@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + dependency-graph@^0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/dependency-graph/-/dependency-graph-0.11.0.tgz#ac0ce7ed68a54da22165a85e97a01d53f5eb2e27" @@ -2875,6 +2993,11 @@ dotenv@^12.0.3: resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-12.0.4.tgz#87e302cfddeef475fcaf9a617f7b44f80ac555bc" integrity sha512-oWdqbSywffzH1l4WXKPHWA0TWYpqp7IyLfqjipT4upoIFS0HPMqtNotykQpD4iIg0BqtNmdgPCh2WMvMt7yTiw== +dotenv@^8.6.0: + version "8.6.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.6.0.tgz#061af664d19f7f4d8fc6e4ff9b584ce237adcb8b" + integrity sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g== + dset@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/dset/-/dset-3.1.1.tgz#07de5af7a8d03eab337ad1a8ba77fe17bba61a8c" @@ -2932,6 +3055,13 @@ emojis-list@^2.0.0: resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k= +encoding@^0.1.12: + version "0.1.13" + resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" + integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A== + dependencies: + iconv-lite "^0.6.2" + end-of-stream@^1.1.0: version "1.4.4" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" @@ -2939,6 +3069,11 @@ end-of-stream@^1.1.0: dependencies: once "^1.4.0" +err-code@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9" + integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA== + error-ex@^1.3.1: version "1.3.2" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" @@ -3369,6 +3504,11 @@ fbjs@^3.0.0: setimmediate "^1.0.5" ua-parser-js "^0.7.30" +fetch-to-curl@^0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fetch-to-curl/-/fetch-to-curl-0.5.2.tgz#9f007ecb3547edeffee49394ff076727dc56d603" + integrity sha512-ygmvsJlU+V4GE91lflkRNAJ956xm5MFl6QukIyxkd6yojTxr6gjp4BsYh7hYXlwVw+ffnMlAIXOTWsWJdk017Q== + figures@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" @@ -3515,6 +3655,13 @@ fragment-cache@^0.2.1: dependencies: map-cache "^0.2.2" +fs-minipass@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" + integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== + dependencies: + minipass "^3.0.0" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -3640,7 +3787,7 @@ glob@7.1.7: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.6, glob@^7.1.7: +glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@^7.1.7: version "7.2.0" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== @@ -3828,11 +3975,20 @@ header-case@^2.0.4: capital-case "^1.0.4" tslib "^2.0.3" -http-cache-semantics@^4.0.0: +http-cache-semantics@^4.0.0, http-cache-semantics@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ== +http-proxy-agent@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" + integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== + dependencies: + "@tootallnate/once" "1" + agent-base "6" + debug "4" + http-proxy-agent@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz#5129800203520d434f142bc78ff3c170800f2b43" @@ -3874,6 +4030,13 @@ iconv-lite@^0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" +iconv-lite@^0.6.2: + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + ieee754@^1.1.13: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" @@ -3941,6 +4104,11 @@ indent-string@^4.0.0: resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== +infer-owner@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" + integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A== + inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" @@ -3995,6 +4163,28 @@ invariant@^2.2.4: dependencies: loose-envify "^1.0.0" +ioredis@^4.28.1, ioredis@^4.28.5: + version "4.28.5" + resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.28.5.tgz#5c149e6a8d76a7f8fa8a504ffc85b7d5b6797f9f" + integrity sha512-3GYo0GJtLqgNXj4YhrisLaNNvWSNwSS2wS4OELGfGxH8I69+XfNdnmV1AyN+ZqMh0i7eX+SWjrwFKDBDgfBC1A== + dependencies: + cluster-key-slot "^1.1.0" + debug "^4.3.1" + denque "^1.1.0" + lodash.defaults "^4.2.0" + lodash.flatten "^4.4.0" + lodash.isarguments "^3.1.0" + p-map "^2.1.0" + redis-commands "1.7.0" + redis-errors "^1.2.0" + redis-parser "^3.0.0" + standard-as-callback "^2.1.0" + +ip@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" + integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= + is-absolute@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-absolute/-/is-absolute-1.0.0.tgz#395e1ae84b11f26ad1795e73c17378e48a301576" @@ -4182,6 +4372,11 @@ is-interactive@^1.0.0: resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e" integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w== +is-lambda@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-lambda/-/is-lambda-1.0.1.tgz#3d9877899e6a53efc0160504cde15f82e6f061d5" + integrity sha1-PZh3iZ5qU+/AFgUEzeFfgubwYdU= + is-lower-case@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/is-lower-case/-/is-lower-case-2.0.2.tgz#1c0884d3012c841556243483aa5d522f47396d2a" @@ -4405,6 +4600,11 @@ json-buffer@3.0.0: resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + json-parse-even-better-errors@^2.3.0: version "2.3.1" resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" @@ -4507,6 +4707,13 @@ keyv@^3.0.0: dependencies: json-buffer "3.0.0" +keyv@^4.0.4: + version "4.1.1" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.1.1.tgz#02c538bfdbd2a9308cc932d4096f05ae42bfa06a" + integrity sha512-tGv1yP6snQVDSM4X6yxrv2zzq/EvpW+oYiUz6aueW1u9CtS8RzUQYxxmFwgZlO2jSgCxQbchhxaqXXp2hnKGpQ== + dependencies: + json-buffer "3.0.1" + kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" @@ -4684,6 +4891,16 @@ lodash.debounce@^4.0.8: resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= +lodash.defaults@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" + integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw= + +lodash.flatten@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" + integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8= + lodash.get@^4: version "4.4.2" resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" @@ -4694,6 +4911,11 @@ lodash.includes@^4.3.0: resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" integrity sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8= +lodash.isarguments@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + integrity sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo= + lodash.isboolean@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" @@ -4793,6 +5015,11 @@ log-update@^4.0.0: slice-ansi "^4.0.0" wrap-ansi "^6.2.0" +loglevel@^1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.8.0.tgz#e7ec73a57e1e7b419cb6c6ac06bf050b67356114" + integrity sha512-G6A/nJLRgWOuuwdNuA6koovfEV1YpqqAG4pRUlFaz3jj2QNZ8M4vBqnVA+HBTmU/AMNUtlOsMmSpF6NyOjztbA== + loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" @@ -4843,6 +5070,27 @@ make-error@^1, make-error@^1.1.1: resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== +make-fetch-happen@^8.0.14: + version "8.0.14" + resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-8.0.14.tgz#aaba73ae0ab5586ad8eaa68bd83332669393e222" + integrity sha512-EsS89h6l4vbfJEtBZnENTOFk8mCRpY5ru36Xe5bcX1KYIli2mkSHqoFsp5O1wMDvTJJzxe/4THpCTtygjeeGWQ== + dependencies: + agentkeepalive "^4.1.3" + cacache "^15.0.5" + http-cache-semantics "^4.1.0" + http-proxy-agent "^4.0.1" + https-proxy-agent "^5.0.0" + is-lambda "^1.0.1" + lru-cache "^6.0.0" + minipass "^3.1.3" + minipass-collect "^1.0.2" + minipass-fetch "^1.3.2" + minipass-flush "^1.0.5" + minipass-pipeline "^1.2.4" + promise-retry "^2.0.1" + socks-proxy-agent "^5.0.0" + ssri "^8.0.0" + map-cache@^0.2.0, map-cache@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" @@ -4967,6 +5215,60 @@ minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== +minipass-collect@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/minipass-collect/-/minipass-collect-1.0.2.tgz#22b813bf745dc6edba2576b940022ad6edc8c617" + integrity sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA== + dependencies: + minipass "^3.0.0" + +minipass-fetch@^1.3.2, minipass-fetch@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-1.4.1.tgz#d75e0091daac1b0ffd7e9d41629faff7d0c1f1b6" + integrity sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw== + dependencies: + minipass "^3.1.0" + minipass-sized "^1.0.3" + minizlib "^2.0.0" + optionalDependencies: + encoding "^0.1.12" + +minipass-flush@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/minipass-flush/-/minipass-flush-1.0.5.tgz#82e7135d7e89a50ffe64610a787953c4c4cbb373" + integrity sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw== + dependencies: + minipass "^3.0.0" + +minipass-pipeline@^1.2.2, minipass-pipeline@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz#68472f79711c084657c067c5c6ad93cddea8214c" + integrity sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A== + dependencies: + minipass "^3.0.0" + +minipass-sized@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/minipass-sized/-/minipass-sized-1.0.3.tgz#70ee5a7c5052070afacfbc22977ea79def353b70" + integrity sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g== + dependencies: + minipass "^3.0.0" + +minipass@^3.0.0, minipass@^3.1.0, minipass@^3.1.1, minipass@^3.1.3: + version "3.1.6" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.6.tgz#3b8150aa688a711a1521af5e8779c1d3bb4f45ee" + integrity sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ== + dependencies: + yallist "^4.0.0" + +minizlib@^2.0.0, minizlib@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" + integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== + dependencies: + minipass "^3.0.0" + yallist "^4.0.0" + mixin-deep@^1.2.0: version "1.3.2" resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" @@ -4980,7 +5282,7 @@ mk-dirs@^1.0.0: resolved "https://registry.yarnpkg.com/mk-dirs/-/mk-dirs-1.0.0.tgz#44ee67f82341c6762718e88e85e577882e1f67fd" integrity sha1-RO5n+CNBxnYnGOiOheV3iC4fZ/0= -mkdirp@^1.0.4: +mkdirp@^1.0.3, mkdirp@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== @@ -5371,7 +5673,7 @@ p-locate@^4.1.0: dependencies: p-limit "^2.2.0" -p-map@^2.0.0: +p-map@^2.0.0, p-map@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== @@ -5816,6 +6118,19 @@ process-nextick-args@~2.0.0: resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== +promise-inflight@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" + integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= + +promise-retry@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-2.0.1.tgz#ff747a13620ab57ba688f5fc67855410c370da22" + integrity sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g== + dependencies: + err-code "^2.0.2" + retry "^0.12.0" + promise@^7.1.1: version "7.3.1" resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" @@ -5850,7 +6165,7 @@ qs@6.7.0: resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== -qs@^6.6.0: +qs@^6.10.2, qs@^6.6.0: version "6.10.3" resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.3.tgz#d6cde1b2ffca87b5aa57889816c5f81535e22e8e" integrity sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ== @@ -6001,6 +6316,23 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" +redis-commands@1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.7.0.tgz#15a6fea2d58281e27b1cd1acfb4b293e278c3a89" + integrity sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ== + +redis-errors@^1.0.0, redis-errors@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad" + integrity sha1-62LSrbFeTq9GEMBK/hUpOEJQq60= + +redis-parser@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4" + integrity sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ= + dependencies: + redis-errors "^1.0.0" + regenerator-runtime@^0.13.2, regenerator-runtime@^0.13.4: version "0.13.9" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" @@ -6185,12 +6517,12 @@ ret@~0.1.10: resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== -retry@0.12.0: +retry@0.12.0, retry@^0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= -retry@0.13.1: +retry@0.13.1, retry@^0.13.1: version "0.13.1" resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== @@ -6267,7 +6599,7 @@ safe-regex@^1.1.0: dependencies: ret "~0.1.10" -"safer-buffer@>= 2.1.2 < 3": +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== @@ -6407,6 +6739,11 @@ slice-ansi@^5.0.0: ansi-styles "^6.0.0" is-fullwidth-code-point "^4.0.0" +smart-buffer@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" + integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== + snake-case@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/snake-case/-/snake-case-3.0.4.tgz#4f2bbd568e9935abdfd593f34c691dadb49c452c" @@ -6445,6 +6782,28 @@ snapdragon@^0.8.1: source-map-resolve "^0.5.0" use "^3.1.0" +snyk@^1.759.0: + version "1.887.0" + resolved "https://registry.yarnpkg.com/snyk/-/snyk-1.887.0.tgz#7bba222689564dde29cc8327e78fafcd6e2a2af1" + integrity sha512-fkTK/V3Bfi14pYyxGgK0QxijRuVTyewTGFsdBOcWmcGw2asAR8ly4nRc/Tk1dtbmfTWHitWbLYT0xPV82NShow== + +socks-proxy-agent@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-5.0.1.tgz#032fb583048a29ebffec2e6a73fca0761f48177e" + integrity sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ== + dependencies: + agent-base "^6.0.2" + debug "4" + socks "^2.3.3" + +socks@^2.3.3: + version "2.6.2" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.6.2.tgz#ec042d7960073d40d94268ff3bb727dc685f111a" + integrity sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA== + dependencies: + ip "^1.1.5" + smart-buffer "^4.2.0" + source-map-js@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" @@ -6503,6 +6862,18 @@ sponge-case@^1.0.1: dependencies: tslib "^2.0.3" +ssri@^8.0.0, ssri@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-8.0.1.tgz#638e4e439e2ffbd2cd289776d5ca457c4f51a2af" + integrity sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ== + dependencies: + minipass "^3.1.1" + +standard-as-callback@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/standard-as-callback/-/standard-as-callback-2.1.0.tgz#8953fc05359868a77b5b9739a665c5977bb7df45" + integrity sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A== + static-extend@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" @@ -6809,6 +7180,18 @@ tailwindcss@^3.0.13: quick-lru "^5.1.1" resolve "^1.21.0" +tar@^6.0.2: + version "6.1.11" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621" + integrity sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA== + dependencies: + chownr "^2.0.0" + fs-minipass "^2.0.0" + minipass "^3.0.0" + minizlib "^2.1.1" + mkdirp "^1.0.3" + yallist "^4.0.0" + taskr@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/taskr/-/taskr-1.1.0.tgz#4f29d0ace26f4deae9a478eabf9aa0432e884438" @@ -6929,12 +7312,12 @@ tsconfig-paths@^3.12.0, tsconfig-paths@^3.9.0: minimist "^1.2.0" strip-bom "^3.0.0" -tslib@^1.0.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: +tslib@^1.0.0, tslib@^1.14.1, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.0, tslib@~2.3.0: +tslib@^2, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.0, tslib@^2.3.1, tslib@~2.3.0: version "2.3.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== @@ -7086,6 +7469,20 @@ union-value@^1.0.0: is-extendable "^0.1.1" set-value "^2.0.1" +unique-filename@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" + integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== + dependencies: + unique-slug "^2.0.0" + +unique-slug@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.2.tgz#baabce91083fc64e945b0f3ad613e264f7cd4e6c" + integrity sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w== + dependencies: + imurmurhash "^0.1.4" + unixify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unixify/-/unixify-1.0.0.tgz#3a641c8c2ffbce4da683a5c70f03a462940c2090"